positivity_final/0000700000175000017500000000000010256226541015633 5ustar duclouxducloux00000000000000positivity_final/globals.h0000600000175000017500000000060510011171251017414 0ustar duclouxducloux00000000000000/* This is globals.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef GLOBALS_H /* guard against multiple inclusions */ #define GLOBALS_H #include #include #include #include #include namespace globals { typedef unsigned long Ulong; /* shorthand */ }; #endif positivity_final/affine.cpp0000600000175000017500000000721010012740005017553 0ustar duclouxducloux00000000000000/* This is affine.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "affine.h" #include "error.h" #include "graph.h" #include "minroots.h" /* local variables */ namespace affine { using namespace error; using namespace graph; using namespace minroots; }; /**************************************************************************** This file contains specific code for affine Coxeter groups. Although there may be more efficient representations for group elements if extremely large elments are required (very compact representations are available that will store elements of essentially unbounded length, certainly many billions without trouble), we have opted for a more uniform treatment and use the minimal root approach. So elements are primarily represented as coxwords. The constructor will attempt to make the minroot table, and if it fails, return an error status. This should fail only in very high rank (more than hundred, say, if then), so it shouldn't cause any real problems. ****************************************************************************/ /**************************************************************************** Chapter 0 -- Initialization. ****************************************************************************/ /**************************************************************************** Chapter I -- Constructors and destructors. This section contains constructors (no destructors!) for the types in this module. - AffineCoxGroup(x,l) : base class for all classes in this module; - AffineBigRankCoxGroup(x,l) : rank > MEDRANK_MAX; - AffineMedRankCoxGroup(x,l) : rank <= MEDRANK_MAX; - AffineSmallRankCoxGroup(x,l) : rank <= MEDRANK_MAX/2; ****************************************************************************/ namespace affine { AffineCoxGroup::AffineCoxGroup(const Type& x, const Rank& l):CoxGroup(x,l) {} AffineCoxGroup::~AffineCoxGroup() /* Virtual destructor for the AffineCoxGroup class. Currently, nothing has to be done. */ {} AffineBigRankCoxGroup::AffineBigRankCoxGroup(const Type& x, const Rank& l) :AffineCoxGroup(x,l) {} AffineBigRankCoxGroup::~AffineBigRankCoxGroup() /* Virtual destructor for the AffineBigRankCoxGroup class. Currently, nothing has to be done. */ {} GeneralABRCoxGroup::GeneralABRCoxGroup(const Type& x, const Rank& l) :AffineBigRankCoxGroup(x,l) {} GeneralABRCoxGroup::~GeneralABRCoxGroup() {} AffineMedRankCoxGroup::AffineMedRankCoxGroup(const Type& x, const Rank& l) :AffineCoxGroup(x,l) { mintable().fill(graph()); /* an error is set here in case of failure */ } AffineMedRankCoxGroup::~AffineMedRankCoxGroup() /* Virtual destructor for the AffineMedRankCoxGroup class. The destruction of the mintable should be the job of the CoxGroup destructor. */ {} GeneralAMRCoxGroup::GeneralAMRCoxGroup(const Type& x, const Rank& l) :AffineMedRankCoxGroup(x,l) {} GeneralAMRCoxGroup::~GeneralAMRCoxGroup() /* Virtual destructor for the GeneralAMRCoxGroup class. Currently, nothing has to be done. */ {} AffineSmallRankCoxGroup::AffineSmallRankCoxGroup(const Type& x, const Rank& l) :AffineMedRankCoxGroup(x,l) {} AffineSmallRankCoxGroup::~AffineSmallRankCoxGroup() /* Virtual destructor for the AffineSmallRankCoxGroup class. Currently, nothing has to be done. */ {} GeneralASRCoxGroup::GeneralASRCoxGroup(const Type& x, const Rank& l) :AffineSmallRankCoxGroup(x,l) {} GeneralASRCoxGroup::~GeneralASRCoxGroup() /* Virtual destructor for the GeneralASRCoxGroup class. Currently, nothing has to be done. */ {} }; positivity_final/makefile0000600000175000017500000002274110256223113017333 0ustar duclouxducloux00000000000000# sources contains a list of the source files (i.e., the .cpp files) sources := $(patsubst %.cpp,%.cpp,$(wildcard *.cpp)) # there is one .o file for each .cpp file objects := $(patsubst %.cpp,%.o,$(wildcard *.cpp)) # this is used to automatically generate the dependencies dependencies := $(patsubst %.cpp,%.d,$(wildcard *.cpp)) globals = globals.h # cflags = -c -g cflags = -c -O cc = g++ all: coxeter clean coxeter: $(objects) # $(cc) -pg -o coxeter $(objects) $(cc) -o coxeter $(objects) clean: rm -f $(objects) %.o:%.cpp $(cc) $(cflags) $*.cpp # dependencies --- these were generated automatically by make depend on my # system; they are explicitly copied for portability. Only local dependencies # are considered. If you add new #include directives you should add the # corresponding dependencies here; the best way if your compiler supports the # -MM option is probably to simply say make depend > tmp, then paste in the # contents of tmp in lieu of the dependencies listed here. %.d:%.cpp @$(cc) -MM $*.cpp depend:$(dependencies) affine.o: affine.cpp affine.h globals.h coxgroup.h coxtypes.h io.h list.h \ memory.h constants.h list.hpp error.h files.h hecke.h interface.h \ automata.h bits.h minroots.h dotval.h graph.h type.h transducer.h \ schubert.h stack.h stack.hpp hecke.hpp polynomials.h vector.h \ vector.hpp polynomials.hpp invkl.h klsupport.h search.h search.hpp kl.h \ uneqkl.h wgraph.h files.hpp cells.h automata.o: automata.cpp automata.h globals.h bits.h list.h memory.h \ constants.h list.hpp error.h io.h bits.o: bits.cpp bits.h globals.h list.h memory.h constants.h list.hpp \ error.h io.h cells.o: cells.cpp cells.h globals.h bits.h list.h memory.h constants.h \ list.hpp error.h io.h kl.h coxtypes.h klsupport.h polynomials.h \ vector.h vector.hpp polynomials.hpp schubert.h interface.h automata.h \ minroots.h dotval.h graph.h type.h transducer.h stack.h stack.hpp \ hecke.h hecke.hpp search.h search.hpp uneqkl.h wgraph.h commands.o: commands.cpp commands.h globals.h coxgroup.h coxtypes.h io.h \ list.h memory.h constants.h list.hpp error.h files.h hecke.h \ interface.h automata.h bits.h minroots.h dotval.h graph.h type.h \ transducer.h schubert.h stack.h stack.hpp hecke.hpp polynomials.h \ vector.h vector.hpp polynomials.hpp invkl.h klsupport.h search.h \ search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h dictionary.h \ dictionary.hpp directories.h fcoxgroup.h help.h interactive.h special.h \ typeA.h constants.o: constants.cpp constants.h globals.h coxgroup.o: coxgroup.cpp coxgroup.h globals.h coxtypes.h io.h list.h \ memory.h constants.h list.hpp error.h files.h hecke.h interface.h \ automata.h bits.h minroots.h dotval.h graph.h type.h transducer.h \ schubert.h stack.h stack.hpp hecke.hpp polynomials.h vector.h \ vector.hpp polynomials.hpp invkl.h klsupport.h search.h search.hpp kl.h \ uneqkl.h wgraph.h files.hpp cells.h coxtypes.o: coxtypes.cpp coxtypes.h globals.h io.h list.h memory.h \ constants.h list.hpp error.h error.o: error.cpp error.h globals.h coxtypes.h io.h list.h memory.h \ constants.h list.hpp directories.h graph.h bits.h type.h interactive.h \ interface.h automata.h minroots.h dotval.h transducer.h kl.h \ klsupport.h polynomials.h vector.h vector.hpp polynomials.hpp \ schubert.h stack.h stack.hpp hecke.h hecke.hpp search.h search.hpp \ version.h fcoxgroup.o: fcoxgroup.cpp fcoxgroup.h globals.h coxgroup.h coxtypes.h \ io.h list.h memory.h constants.h list.hpp error.h files.h hecke.h \ interface.h automata.h bits.h minroots.h dotval.h graph.h type.h \ transducer.h schubert.h stack.h stack.hpp hecke.hpp polynomials.h \ vector.h vector.hpp polynomials.hpp invkl.h klsupport.h search.h \ search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h files.o: files.cpp files.h globals.h hecke.h list.h memory.h constants.h \ list.hpp error.h interface.h automata.h bits.h io.h coxtypes.h \ minroots.h dotval.h graph.h type.h transducer.h schubert.h stack.h \ stack.hpp hecke.hpp polynomials.h vector.h vector.hpp polynomials.hpp \ invkl.h klsupport.h search.h search.hpp kl.h uneqkl.h wgraph.h \ files.hpp cells.h directories.h posets.h version.h general.o: general.cpp general.h globals.h coxgroup.h coxtypes.h io.h \ list.h memory.h constants.h list.hpp error.h files.h hecke.h \ interface.h automata.h bits.h minroots.h dotval.h graph.h type.h \ transducer.h schubert.h stack.h stack.hpp hecke.hpp polynomials.h \ vector.h vector.hpp polynomials.hpp invkl.h klsupport.h search.h \ search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h graph.o: graph.cpp graph.h globals.h list.h memory.h constants.h list.hpp \ error.h bits.h io.h coxtypes.h type.h directories.h interactive.h \ interface.h automata.h minroots.h dotval.h transducer.h hecke.o: hecke.cpp help.o: help.cpp help.h globals.h commands.h coxgroup.h coxtypes.h io.h \ list.h memory.h constants.h list.hpp error.h files.h hecke.h \ interface.h automata.h bits.h minroots.h dotval.h graph.h type.h \ transducer.h schubert.h stack.h stack.hpp hecke.hpp polynomials.h \ vector.h vector.hpp polynomials.hpp invkl.h klsupport.h search.h \ search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h dictionary.h \ dictionary.hpp directories.h interactive.o: interactive.cpp interactive.h globals.h bits.h list.h \ memory.h constants.h list.hpp error.h io.h coxtypes.h graph.h type.h \ interface.h automata.h minroots.h dotval.h transducer.h affine.h \ coxgroup.h files.h hecke.h schubert.h stack.h stack.hpp hecke.hpp \ polynomials.h vector.h vector.hpp polynomials.hpp invkl.h klsupport.h \ search.h search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h \ directories.h fcoxgroup.h general.h typeA.h interface.o: interface.cpp interface.h globals.h automata.h bits.h list.h \ memory.h constants.h list.hpp error.h io.h coxtypes.h minroots.h \ dotval.h graph.h type.h transducer.h invkl.o: invkl.cpp invkl.h globals.h coxtypes.h io.h list.h memory.h \ constants.h list.hpp error.h klsupport.h polynomials.h vector.h \ vector.hpp polynomials.hpp schubert.h bits.h interface.h automata.h \ minroots.h dotval.h graph.h type.h transducer.h stack.h stack.hpp \ hecke.h hecke.hpp search.h search.hpp io.o: io.cpp io.h globals.h list.h memory.h constants.h list.hpp error.h kl.o: kl.cpp kl.h globals.h coxtypes.h io.h list.h memory.h constants.h \ list.hpp error.h klsupport.h polynomials.h vector.h vector.hpp \ polynomials.hpp schubert.h bits.h interface.h automata.h minroots.h \ dotval.h graph.h type.h transducer.h stack.h stack.hpp hecke.h \ hecke.hpp search.h search.hpp iterator.h klsupport.o: klsupport.cpp klsupport.h globals.h coxtypes.h io.h list.h \ memory.h constants.h list.hpp error.h polynomials.h vector.h vector.hpp \ polynomials.hpp schubert.h bits.h interface.h automata.h minroots.h \ dotval.h graph.h type.h transducer.h stack.h stack.hpp main.o: main.cpp constants.h globals.h commands.h coxgroup.h coxtypes.h \ io.h list.h memory.h list.hpp error.h files.h hecke.h interface.h \ automata.h bits.h minroots.h dotval.h graph.h type.h transducer.h \ schubert.h stack.h stack.hpp hecke.hpp polynomials.h vector.h \ vector.hpp polynomials.hpp invkl.h klsupport.h search.h search.hpp kl.h \ uneqkl.h wgraph.h files.hpp cells.h dictionary.h dictionary.hpp \ version.h memory.o: memory.cpp memory.h globals.h constants.h error.h minroots.o: minroots.cpp minroots.h globals.h bits.h list.h memory.h \ constants.h list.hpp error.h io.h coxtypes.h dotval.h graph.h type.h polynomials.o: polynomials.cpp posets.o: posets.cpp posets.h globals.h bits.h list.h memory.h \ constants.h list.hpp error.h io.h wgraph.h interface.h automata.h \ coxtypes.h minroots.h dotval.h graph.h type.h transducer.h schubert.o: schubert.cpp schubert.h globals.h coxtypes.h io.h list.h \ memory.h constants.h list.hpp error.h bits.h interface.h automata.h \ minroots.h dotval.h graph.h type.h transducer.h stack.h stack.hpp search.o: search.cpp special.o: special.cpp special.h globals.h commands.h coxgroup.h \ coxtypes.h io.h list.h memory.h constants.h list.hpp error.h files.h \ hecke.h interface.h automata.h bits.h minroots.h dotval.h graph.h \ type.h transducer.h schubert.h stack.h stack.hpp hecke.hpp \ polynomials.h vector.h vector.hpp polynomials.hpp invkl.h klsupport.h \ search.h search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h \ dictionary.h dictionary.hpp directories.h interactive.h stack.o: stack.cpp transducer.o: transducer.cpp transducer.h globals.h coxtypes.h io.h \ list.h memory.h constants.h list.hpp error.h graph.h bits.h type.h type.o: type.cpp type.h globals.h io.h list.h memory.h constants.h \ list.hpp error.h typeA.o: typeA.cpp typeA.h globals.h fcoxgroup.h coxgroup.h coxtypes.h \ io.h list.h memory.h constants.h list.hpp error.h files.h hecke.h \ interface.h automata.h bits.h minroots.h dotval.h graph.h type.h \ transducer.h schubert.h stack.h stack.hpp hecke.hpp polynomials.h \ vector.h vector.hpp polynomials.hpp invkl.h klsupport.h search.h \ search.hpp kl.h uneqkl.h wgraph.h files.hpp cells.h uneqkl.o: uneqkl.cpp uneqkl.h globals.h coxtypes.h io.h list.h memory.h \ constants.h list.hpp error.h hecke.h interface.h automata.h bits.h \ minroots.h dotval.h graph.h type.h transducer.h schubert.h stack.h \ stack.hpp hecke.hpp polynomials.h vector.h vector.hpp polynomials.hpp \ klsupport.h search.h search.hpp interactive.h vector.o: vector.cpp wgraph.o: wgraph.cpp wgraph.h globals.h list.h memory.h constants.h \ list.hpp error.h bits.h io.h interface.h automata.h coxtypes.h \ minroots.h dotval.h graph.h type.h transducer.h stack.h stack.hpp positivity_final/affine.h0000600000175000017500000000653310011171251017227 0ustar duclouxducloux00000000000000/* This is affine.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef AFFINE_H /* guarantee single inclusion */ #define AFFINE_H #include "globals.h" #include "coxgroup.h" namespace affine { using namespace globals; using namespace coxgroup; }; /******** type declarations *************************************************/ namespace affine { class AffineCoxGroup; class AffineBigRankCoxGroup; class GeneralABRCoxGroup; class AffineMedRankCoxGroup; class GeneralAMRCoxGroup; class AffineSmallRankCoxGroup; class GeneralASRCoxGroup; }; /******** type definitions **************************************************/ namespace affine { class AffineCoxGroup : public CoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(AffineCoxGroup));} AffineCoxGroup(const Type& x, const Rank& l); virtual ~AffineCoxGroup(); /* accessors */ CoxSize order() const; /* inlined */ }; class AffineBigRankCoxGroup : public AffineCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(AffineBigRankCoxGroup));} AffineBigRankCoxGroup(const Type& x, const Rank& l); virtual ~AffineBigRankCoxGroup(); }; class GeneralABRCoxGroup:public AffineBigRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralABRCoxGroup));} GeneralABRCoxGroup(const Type& x, const Rank& l); ~GeneralABRCoxGroup(); }; class AffineMedRankCoxGroup : public AffineCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(AffineMedRankCoxGroup));} AffineMedRankCoxGroup(const Type& x, const Rank& l); virtual ~AffineMedRankCoxGroup(); }; class GeneralAMRCoxGroup:public AffineMedRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralAMRCoxGroup));} GeneralAMRCoxGroup(const Type& x, const Rank& l); ~GeneralAMRCoxGroup(); }; class AffineSmallRankCoxGroup : public AffineMedRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(AffineSmallRankCoxGroup));} AffineSmallRankCoxGroup(const Type& x, const Rank& l); virtual ~AffineSmallRankCoxGroup(); }; class GeneralASRCoxGroup:public AffineSmallRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralASRCoxGroup));} GeneralASRCoxGroup(const Type& x, const Rank& l); ~GeneralASRCoxGroup(); }; }; /******** Inline implementations ******************************************/ namespace affine { inline CoxSize AffineCoxGroup::order() const {return infinite_coxsize;} }; #endif positivity_final/automata.cpp0000600000175000017500000000443210011171251020141 0ustar duclouxducloux00000000000000/* This is automata.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "automata.h" #include "memory.h" namespace automata { using namespace memory; }; /**************************************************************************** This file regroups the stuff about finite state automata that will be needed in this program. It might grow rather large --- and even be split over several files --- over time. Potentially the role of automata is huge. After the proof by Brink and Howlett of the rationality of the ShortLex language for any Coxeter group and any ordering of the generator set, one can ask for the finite state automaton in each case. Even more important, I believe, is the case of quotients : as spectacularly illustrated by Casselman for type E, finite state automata might be the best (the only ?) way of traversing parabolic quotients in a reasonable time. Also, for the finite case at least, their size is really quite manageable. ****************************************************************************/ /**************************************************************************** Chapter I -- The ExplicitAutomaton class. An ExplicitAutomaton object is an implementation of the Automaton class where all the data are just explicitly written down in tables : the state transitions are in one big table, and the accept states are marked off in a bitmap. ****************************************************************************/ namespace automata { ExplicitAutomaton::ExplicitAutomaton(Ulong n, Ulong m) :d_accept(n),d_rank(m),d_size(n) { d_table = (State **)arena().alloc(d_size*sizeof(Ulong *)); d_table[0] = (State *)arena().alloc(d_size*d_rank*sizeof(Ulong)); for (Ulong j = 1; j < d_size; ++j) d_table[j] = d_table[j-1] + d_rank; } ExplicitAutomaton::~ExplicitAutomaton() /* The memory allocated directly by ExplicitAutomaton is the one for the table, and for the pointers to the rows. Recall that the number of states is recorded in d_size, the number of letters in the alphabet in d_rank. Hence we have the size of our allocation. */ { arena().free(d_table[0],d_size*d_rank*sizeof(Ulong)); arena().free(d_table,d_size*sizeof(Ulong *)); } }; positivity_final/automata.h0000600000175000017500000000556110011171251017612 0ustar duclouxducloux00000000000000/* This is automata.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef AUTOMATA_H /* guard against multiple inclusions */ #define AUTOMATA_H #include "globals.h" namespace automata { using namespace globals; }; /******** type declarations **************************************************/ namespace automata { class Automaton; class ExplicitAutomaton; typedef unsigned Letter; typedef unsigned State; }; /******** type definitions ***************************************************/ #include "bits.h" namespace automata { class Automaton { public: /* accessors */ virtual State act(State x, Letter a) const = 0; virtual State initialState() const = 0; virtual bool isAccept(State x) const = 0; virtual bool isFailure(State x) const = 0; virtual Ulong rank() const = 0; virtual Ulong size() const = 0; }; class ExplicitAutomaton:public Automaton { private: State **d_table; bits::BitMap d_accept; State d_failure; State d_initial; Ulong d_rank; Ulong d_size; public: /* constructors and destructors */ ExplicitAutomaton(Ulong n, Ulong m); virtual ~ExplicitAutomaton(); /* manipulators */ void setAccept(State x); /* inlined */ void setFailure(State x); /* inlined */ void setInitial(State x); /* inlined */ void setTable(State x, Letter a, State xa); /* inlined */ /* accessors */ State act(State x, Letter a) const; /* inlined */ State initialState() const; /* inlined */ bool isAccept(State x) const; /* inlined */ bool isFailure(State x) const; /* inlined */ Ulong rank() const; /* inlined */ Ulong size() const; /* inlined */ }; }; /******** inline implementations ******************************************/ namespace automata { inline void ExplicitAutomaton::setAccept(State x) {d_accept.setBit(x);} inline void ExplicitAutomaton::setFailure(State x) {d_failure = x;} inline void ExplicitAutomaton::setInitial(State x) {d_initial = x;} inline void ExplicitAutomaton::setTable(State x, Letter a, State xa) {d_table[x][a] = xa;} inline State ExplicitAutomaton::act(State x, Letter a) const {return d_table[x][a];} inline State ExplicitAutomaton::initialState() const {return d_initial;} inline bool ExplicitAutomaton::isAccept(State x) const {return d_accept.getBit(x);} inline bool ExplicitAutomaton::isFailure(State x) const {return x == d_failure;} inline Ulong ExplicitAutomaton::rank() const {return d_rank;} inline Ulong ExplicitAutomaton::size() const {return d_size;} }; #endif positivity_final/bits.cpp0000600000175000017500000006260410014466567017320 0ustar duclouxducloux00000000000000/* This is bits.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "bits.h" #include /***************************************************************************** This module regroups classes and functions for bit-access of structures. Subsets of given structures will frequently in this program be represented by bitmaps; these may be small bitmaps, fitting inside a single Ulong, or larger ones, necessitating a list. In this program, a bitmap will always be a list of unsigned chars, ensuring portability across all platforms, independently of word size and endianism problems. However, to accelerate bitwise operations we always make sure that bitmaps are allocated in multiples of sizeof(Ulong) characters, so that bitwise operations can be done one Ulong at a time. *****************************************************************************/ /***************************************************************************** Chapter I -- The Permutation class A permutation of a set is just the enumeration of the elements of the set (assumed to be running from 0 to N-1) in a certain order; a[j] is interpreted as the image of element #j under a. We have tried to be consistent in the whole program about this, and the way permutations acts on sets and functions; when a acts on the range, we somply apply a to the image of a function; when a acts on the domain, we compose f with a^{-1} (we are able to do this essentially in-place.) The following functions are defined : - constructors and destructors : - Permutation(); - Permutation(n); - ~Permutation(); - manipulators : - inverse() : inverts the permutation; - compose(a) : increment by a under right composition; - leftCompose(a) : same on the left; *****************************************************************************/ namespace bits { Permutation::Permutation():List() {} Permutation::Permutation(const Ulong& n):List(n) {} Permutation::~Permutation() {} Permutation& Permutation::identity(const Ulong& n) /* Sets the permutation to the identity permutation of [0,n[. */ { setSize(n); for (Ulong j = 0; j < size(); ++j) { d_ptr[j] = j; } return *this; } Permutation& Permutation::inverse() /* Inverts the current permutation : new(old(x)) = x. This is a little bit more tricky than our usual inversions, because it involves the permutation itselves; we've opted for safety and used a buffer for the whole permutation. */ { static Permutation i(0); i.setSize(size()); Permutation& t = *this; for (SetElt x = 0; x < size(); ++x) i[t[x]] = x; t.assign(i); return t; } Permutation& Permutation::rightCompose(const Permutation& a) /* Increments the current permutation by composition on the right with a : new(x) = old(a(x)). The same problem occurs as with inverse. */ { static Permutation c(0); c.setSize(size()); Permutation& t = *this; for (SetElt x = 0; x < size(); ++x) c[x] = t[a[x]]; t.assign(c); return t; } Permutation& Permutation::compose(const Permutation& a) /* Increments the current permutation by composition on the left with a : new(x) = a(old(x)). */ { for (SetElt x = 0; x < size(); ++x) operator[](x) = a[operator[](x)]; return *this; } }; /***************************************************************************** Chapter II -- The BitMap class. The following functions are defined for BitMap : - constructors : - BitMap(Ulong n); - ~BitMap() : standard destructor; - accessors : - bitCount() : returns the number of set bits; - firstBit() : returns the bit-address of the first set bit; - getBit(n) : checks if bit n is set; - isEmpty(m) : checks if [m,->[ is empty; - lastBit() : returns the bit-address of the last set bit; - modifiers : - assign(map) : sets the bitmap equal to map, resizing if necessary; - clearBit(n) : clears bit n; (inlined) - permute(q) : applies q to the bitmap; - setBit(n) : sets bit n; (inlined) - setSize(n) : resizes the bitmap to size n; - operations : - operator~ () : changes into opposite bitmap; - operator&= (map) : intersects with map; - operator|= (map) : does union with map; - andnot(map) : intersects with the negative of map; *****************************************************************************/ namespace bits { /********** constructors and destructors *************************************/ BitMap::BitMap(const Ulong& n) :d_map(n/BITS(LFlags)+(bool)(n%BITS(LFlags))), d_size(n) /* Constructor for the BitMap class; constructs a bitmap capable of holding n bits. */ { d_map.setSize(n/BITS(LFlags)+(bool)(n%BITS(LFlags))); } BitMap::~BitMap() /* No memory is directly allocated by BitMap. */ {} /********** accessors ********************************************************/ Ulong BitMap::bitCount() const /* Returns the number of set bits in the bitmap. */ { Ulong count = 0; for (Ulong j = 0; j < d_map.size(); ++j) count += bits::bitCount(d_map[j]); return count; } Ulong BitMap::firstBit() const /* Returns the bit position of the first set bit. */ { Ulong first = 0; LFlags f = (LFlags)1; for (Ulong j = 0; j < d_map.size(); ++j) { if (d_map[j]) { /* first bit found */ f = d_map[j]; return f; } else first += BITS(LFlags); } return first + bits::firstBit(f); } bool BitMap::isEmpty(const Ulong& m) const /* This function checks whether the intersection of the bitmap with the interval [m,size[ is empty */ { Ulong lsize = d_size/BITS(LFlags)+(bool)(d_size%BITS(LFlags)); /* look at word containing m */ Ulong ml = m/BITS(LFlags); Ulong mr = m%BITS(LFlags); Ulong mc = BITS(LFlags)-1 - mr; LFlags f = leqmask[mc] << mr; if (d_map[ml]&f) return(false); for (Ulong j = ml+1; j < lsize; ++j) { if (d_map[j]) return false; } return true; } Ulong BitMap::lastBit() const /* This function returns the bit-address of the last set bit in b. The return value is b.size() if b is empty. */ { if (d_size == 0) return 0; Ulong base = (d_size-1)/BITS(LFlags)+1; while(base) { base--; LFlags f = d_map[base]; if (f) return (base*BITS(LFlags)+constants::lastBit(f)); } /* if we reach this point, the bitmap is empty */ return (d_size); } /********** modifiers ********************************************************/ BitMap& BitMap::assign(const BitMap& map) /* Copies the content of map into the current map. */ { d_map.assign(map.d_map); d_size = map.d_size; return *this; } void BitMap::permute(Permutation& q) /* This function applies the permutation q to the bitmap b. Here b is interpreted as a bool-valued table; we want that b[q[x]] hold the value previously held by b[x]. This is a range-permutation, as explained in kl.cpp. */ { static BitMap b(0); b.setSize(q.size()); b.reset(); for (Ulong i = 0; i < d_size; ++i) { if (b.getBit(i)) continue; for (Ulong j = q[i]; j != i; j = q[j]) { bool t = getBit(j); setBit(j,getBit(i)); setBit(i,t); b.setBit(j); } b.setBit(i); } return; } void BitMap::setSize(const Ulong& n) /* Resizes the bitmap to hold n bits. If the size grows, it is guaranteed that the new bits are set to zero. */ { d_map.setSize(n/BITS(LFlags) + (bool)(n%BITS(LFlags))); if (n > size()) { /* set new bits to zero */ Ulong f = size()/BITS(LFlags); /* word holding first new bit */ Ulong fb = size()%BITS(LFlags); /* bit address of first new bit in f */ LFlags old = ((1L << fb) - 1L); /* flags old bits */ d_map[f] &= old; d_map.setZero(f+1,d_map.size()-f-1); } d_size = n; } /********** operators ********************************************************/ void BitMap::operator~ () /* Transforms the bitmap into its complement. One has to be careful not to exceed the size of the bitmap! */ { for (Ulong j = 0; j < d_map.size(); ++j) d_map[j] = ~d_map[j]; d_map[d_map.size()-1] &= lastchunk(); return; } void BitMap::operator&= (const BitMap& map) /* Does the bitwise intersection with map. It is assumed that map has at least size size(). */ { for (Ulong j = 0; j < d_map.size(); ++j) d_map[j] &= map.chunk(j); return; } void BitMap::operator|= (const BitMap& map) /* Does the bitwise union with map. It is assumed that map has at least size size(). */ { for (Ulong j = 0; j < d_map.size(); ++j) d_map[j] |= map.chunk(j); return; } void BitMap::andnot(const BitMap& map) /* Does the bitwise intersection with ~map. It is assumed that map has at least size size(). */ { for (Ulong j = 0; j < d_map.size(); ++j) d_map[j] &= ~(map.chunk(j)); return; } }; /**************************************************************************** Chapter III -- The Iterator class. This is my first attempt at an STL-style iterator. I'm not trying to stick exactly to the stl-notation and requirements, but I hope to be in the right spirit. The Iterator class for bitmaps is bidirectional; it traverses the set bits for the bitmap. The only constructors are for begin() (an iterator pointing to the first non-zero element) and end (a non-dereferenceable, past-the-end iterator.) It is guaranteed that begin() == end() if the bitmap is empty (i.e. bitCount returns zero.) The data in the Iterator class have the following meaning. Recall that a BitMap is implemented as a list of LFlags. There is a current such LFlag, which is pointed by d_chunk; d_bitAddress is the bit address of the current set bit. The past-the-end iterator is the one with bitAddress equal to the size of the bitmap. The following functions are defined : - Iterator(const BitMap&, bool) : constructs begin() if true, end() if false; - operator* () : returns the position of the current bit; - operator++ () : moves to the next set bit, or past-the-end; - operator-- () : moves to the previous set bit (valid if iterator is not begin()); - operator== (i) : says if the two iterators point to the same bit-address; (inlined); - operator!= (i) : the negation of operator==. ****************************************************************************/ namespace bits { BitMap::Iterator::Iterator() {} BitMap::Iterator::Iterator(const BitMap& b) :d_b(&b) /* Constructs begin(). */ { d_chunk = d_b->d_map.ptr(); d_bitAddress = 0; for (d_bitAddress = 0; d_bitAddress < d_b->size(); d_bitAddress += BITS(LFlags)) { if (*d_chunk) { d_bitAddress += bits::firstBit(*d_chunk); break; } ++d_chunk; } if (d_bitAddress > d_b->size()) /* bitmap was empty */ d_bitAddress = d_b->size(); } BitMap::Iterator::~Iterator() /* Automatic destruction is enough. */ {} BitMap::Iterator& BitMap::Iterator::operator++ () /* Increment operator (prefix notation). Valid if the iterator is dereferenceable. Result is dereferenceable or past-the-end. */ { LFlags f = *d_chunk >> bitPos(); f >>= 1; if (f) { d_bitAddress += bits::firstBit(f)+1; } else { /* go to next chunk */ d_bitAddress &= baseBits; ++d_chunk; for (d_bitAddress += BITS(LFlags) ; d_bitAddress < d_b->size(); d_bitAddress += BITS(LFlags)) { if (*d_chunk) { d_bitAddress += bits::firstBit(*d_chunk); break; } ++d_chunk; } if (d_bitAddress > d_b->size()) d_bitAddress = d_b->size(); } return *this; } BitMap::Iterator& BitMap::Iterator::operator-- () /* Decrement operator (prefix notation). Valid if the iterator is past-the-end, or is dereferenceable and not equal to begin(). */ { LFlags f = 0; if (bitPos()) { f = *d_chunk & leqmask[bitPos()-1]; } if (f) { d_bitAddress &= baseBits; d_bitAddress += bits::lastBit(f); } else { /* go to previous chunk */ d_bitAddress &= baseBits; while (d_bitAddress) { d_bitAddress -= BITS(LFlags); --d_chunk; if (*d_chunk) { d_bitAddress += bits::lastBit(*d_chunk); break; } } } return *this; } BitMap::Iterator BitMap::begin() const /* Returns */ { static Iterator i; new(&i) Iterator(*this); return i; } BitMap::Iterator BitMap::end() const { static Iterator i; i.d_b = this; i.d_bitAddress = d_size; i.d_chunk = d_map.ptr()+d_map.size(); if (i.bitPos()) i.d_chunk--; return i; } }; /**************************************************************************** Chapter IV -- The Partition class A partition of a set is represented by a function of the set to the range [0,N[, where N is the number of classes in the partition. Moreover it is useful to have direct access to the number of classes. The following functions are defined : - constructors and destructors : - Partition(); - Partition(n) : constructs a partition with a list of size n; - ~Partition() (inlined); - accessors : - classCount() : returns the number of classes; (inlined) - sort(v) : returns a permutation vector of the set, so that classes are contiguous and sorted in their original order; - writeClass(b,n) : sets b to hold class #n; - modifiers : - normalize() : normalizes the permutation; - normalize(a) : writes the normalizing permutation in a; - permute(a) : permutes the partition according to a; - setClassCount(n) : sets the number of classes to n; - setClassCount() : fill in the number of classes; - input/output : - printClassSizes(file) : prints the sizes of the classes; NOTE : this class really has nothing to do with bits. It should probably be moved to another module (maybe sort.h, or sets.h ?) ****************************************************************************/ namespace bits { Partition::Partition() {} Partition::Partition(const Ulong &n):d_list(n),d_classCount(0) { d_list.setSize(n); } Partition::~Partition() /* No memory is directly allocated by the Partition constructors. */ {} /******* accessors **********************************************************/ void Partition::sort(Permutation& a) const /* Puts in a the permutation vector for which the classes are contiguous, in increasing order, and each class is in the enumeration order of the original set. In other words, we have new[a[j]] = old[j]. We do this by counting each class, then putting each element directly in its right place in a. */ { if (size() == 0) return; static List count(0); /* count class cardinalities */ count.setSize(d_classCount); count.setZero(); for (Ulong j = 0; j < size(); ++j) { count[d_list[j]]++; } /* put class offsets in count */ count.setData(count.ptr(),1,count.size()-1); for (Ulong j = 2; j < count.size(); ++j) count[j] += count[j-1]; count[0] = 0; /* fill permutation */ a.setSize(size()); for (Ulong j = 0; j < size(); ++j) { Ulong k = d_list[j]; a[j] = count[k]; count[k]++; } } void Partition::sortI(Permutation& a) const /* Like sort, but returns the inverse permutation directly. This is in fact used more frequently then sort, because the permutation returned by shortI is the one we need for the traversal of the classes. Here we have new[j] = old[a[j]]. */ { if (size() == 0) return; static List count(0); /* count class cardinalities */ count.setSize(d_classCount); count.setZero(); for (Ulong j = 0; j < size(); ++j) { count[d_list[j]]++; } /* put class offsets in count */ count.setData(count.ptr(),1,count.size()-1); for (Ulong j = 2; j < count.size(); ++j) count[j] += count[j-1]; count[0] = 0; /* fill permutation */ a.setSize(size()); for (Ulong j = 0; j < size(); ++j) { Ulong k = d_list[j]; a[count[k]] = j; count[k]++; } } void Partition::writeClass(BitMap& b, const Ulong& n) const /* This function sets the bitmap to the bitmap of class #n. It is assumed that b.size() is equal to size(). */ { b.reset(); for (Ulong j = 0; j < size(); ++j) { if (d_list[j] == n) b.setBit(j); } return; } /******* modifiers **********************************************************/ void Partition::normalize() /* Normalizes the partition by reordering the classes in the order of their first elements. Hence, two normalized partitions are equal as partitions iff they are equal as functions. */ { static List a(0); static BitMap b(0); a.setSize(d_classCount); b.setSize(d_classCount); b.reset(); Ulong count = 0; for (Ulong j = 0; j < size(); ++j) { if (!b.getBit(d_list[j])) { /* new value */ b.setBit(d_list[j]); a[d_list[j]] = count; count++; } } /* now a[k] is the order of appearance of value #k */ for (Ulong j = 0; j < size(); ++j) { d_list[j] = a[d_list[j]]; } return; } void Partition::normalize(Permutation& a) /* Same as normalize(), but records the permutation in a. */ { static BitMap b(0); a.setSize(d_classCount); b.setSize(d_classCount); b.reset(); Ulong count = 0; for (Ulong j = 0; j < size(); ++j) { if (!b.getBit(d_list[j])) { /* new value */ b.setBit(d_list[j]); a[d_list[j]] = count; count++; } } /* now a[k] is the order of appearance of value #k */ for (Ulong j = 0; j < size(); ++j) { d_list[j] = a[d_list[j]]; } return; } void Partition::permute(const Permutation& a) /* Permutes the partition according to a (i.e., apply a to the domain of the partition function.) */ { static BitMap b(0); b.setSize(size()); b.reset(); for (SetElt x = 0; x < size(); ++x) { if (b.getBit(x)) continue; for (SetElt y = a[x]; y != x; y = a[y]) { Ulong buf = d_list[y]; d_list[y] = d_list[x]; d_list[x] = buf; b.setBit(y); } b.setBit(x); } return; } void Partition::permuteRange(const Permutation& a) /* Applies the permutation a to the range of the partition function. */ { for (SetElt x = 0; x < size(); ++x) d_list[x] = a[d_list[x]]; return; } void Partition::setClassCount() /* Finds the number of classes. */ { Ulong count = 0; for (Ulong j = 0; j < size(); ++j) { if (d_list[j] >= count) count = d_list[j]+1; } d_classCount = count; return; } /******** input/output ******************************************************/ void Partition::printClassSizes(FILE* file) const /* This function prints out the sizes of the classes in the partition. */ { static List count(0); count.setSize(d_classCount); count.setZero(); for (Ulong j = 0; j < size(); ++j) { count[d_list[j]]++; } for (Ulong j = 0; j < d_classCount; ++j) { fprintf(file,"%lu",count[j]); if (j < d_classCount-1) fprintf(file,","); } fprintf(file,"\n"); return; } }; /**************************************************************************** Chapter V -- The PartitionIterator class. This class is intended for the convenient traversal of a partition. At each iteration, a new class is provide as a list (maybe this should become a SubSet ?). To do this conveniently, a permutation d_a is used to sort the partition by contiguous classes. The current class is kept in d_class. ****************************************************************************/ namespace bits { PartitionIterator::PartitionIterator(const Partition& pi) :d_pi(pi),d_a(pi.size()),d_class(0),d_base(0),d_valid(true) /* */ { if (pi.size() == 0) { d_valid = false; goto done; } { d_a.setSize(pi.size()); pi.sortI(d_a); /* load first class */ Ulong j = 0; for (; (j < d_a.size()) && (d_pi(d_a[j]) == d_pi(d_a[d_base])); ++j) { d_class.append(d_a[j]); } } done: ; } PartitionIterator::~PartitionIterator() /* Automatic destruction suffices. */ {} void PartitionIterator::operator++ () { d_base += d_class.size(); if (d_base == d_pi.size()) { d_valid = false; return; } Ulong j = d_base; d_class.setSize(0); for (; (j < d_a.size()) && (d_pi(d_a[j]) == d_pi(d_a[d_base])); ++j) { d_class.append(d_a[j]); } } }; /**************************************************************************** Chapter VI -- The SubSet class. The SubSet class is designed to hold subsets of enumerated sets. Typically, we will want to know which elements are in the subset, and also, to have a quick way of deciding whether an arbitrary element is in it. We implement this using a list of the elements in the subset, and a bitmap describing the subset within the big set. Of course everything could be done just from the bitmap, but this would slow down traversal somewhat. (Otherwise we would have to write an iterator directly from the bitmap, doubtless a worthwile exercise.) The following functions are defined : - constructors and destructors : - SubSet(n) : constructs a subset with a bitmap of size n; (inlined) - ~SubSet() : standard destructor (inlined); - accessors : - isMember(n) : tells if element #n is a member of the subset; (inlined) - size() : number of elements in the subset; (inlined) - modifiers : - add(n) : adds element n to the subset; - readBitMap() : reads the contents of the bitmap into the list; - reset() : resets the subset to the empty subset; *****************************************************************************/ namespace bits { SubSet::~SubSet() /* No memory is directly allocated by a SubSet constructor. */ {} void SubSet::add(const Ulong& n) /* Adds a new element to the subset. It is assumed that n is a legal value w.r.t. the bitmap. We do not sort the elements in order; some special function should take care of that if required. Forwards the error MEMORY_WARNING if CATCH_MEMORY_OVERFLOW is set. */ { if (d_bitmap.getBit(n)) /* n is already in there */ return; d_bitmap.setBit(n); d_list.append(n); /* the error OUT_OF_MEMORY may have been set here */ return; } void SubSet::readBitMap() /* Puts the content of the bitmap in the list in a simple-minded way. */ { d_list.setSize(d_bitmap.bitCount()); BitMap::Iterator i = d_bitmap.begin(); for (Ulong j = 0; j < d_list.size(); ++j) { d_list[j] = *i; ++i; } return; } void SubSet::reset() /* Resets the SubSet to represent the empty set. */ { d_bitmap.reset(); d_list.setSize(0); return; } }; /***************************************************************************** Chapter VII -- Counting bits. This section contains functions for counting bits in bitmaps : - bitCount(f) : counts the number of set bits in an LFlags; *****************************************************************************/ unsigned bits::bitCount(const LFlags& d_f) /* Returns the number of set bits in f. */ { unsigned count; count = 0; for (LFlags f = d_f; f; f &= f-1) count++; /* see K&R */ return count; } /***************************************************************************** Chapter VIII -- Copying memory. This section contains functions for copying memory between bitmaps : - MemSet(dest,source,size,count) : copies into dest count repetitions of the pattern made up by the first size bits in source; *****************************************************************************/ void bits::memSet(void *dest, void *source, Ulong size, Ulong count) /* Copies into dest count repetitions of the pattern made up by the first size bits in source. */ { Ulong c; if (count == 0) return; memmove(dest,source,size); source = dest; dest = (void *)((char *)dest + size); for (c = 1; c <= count/2; c *= 2) { memmove(dest,source,c*size); dest = (void *)((char *)dest + c*size); } memmove(dest,source,(count-c)*size); return; } /***************************************************************************** Chapter IX -- Input/Output. This section contains i/o functions for the classes defined in this module : - append(l,map) : appends the BitMap map to the string l; - print(file,map) : prints the map to the file; *****************************************************************************/ namespace bits { String& append(String& l, const BitMap& map) /* Appends the map to the string. Uses a representation in terms of zeroes and ones. */ { for (Ulong j = 0; j < map.size(); ++j) { if (map.getBit(j)) /* bit is set */ append(l,"1"); else append(l,"0"); } return l; } void print(FILE* file, const BitMap& map) /* Prints the map to the file. Uses append. */ { static String buf(0); reset(buf); append(buf,map); print(file,buf); return; } }; /***************************************************************************** Chapter X -- Utilities. This section contains various utility functions : - isRefinement(pi1,pi2) : tells whether pi1 is a refinement of pi2; *****************************************************************************/ namespace bits { bool isRefinement(const Partition& pi1, const Partition& pi2) /* Tells whether pi1 is a refinement of pi2. Both are assumed to be partitions of the same range; the condition is that pi2 should be constant on the classes of pi1. */ { for (PartitionIterator i(pi1); i; ++i) { const Set& l = i(); Ulong a = pi2(l[0]); for (Ulong j = 1; j < l.size(); ++j) if (pi2(l[j]) != a) return false; } return true; } }; positivity_final/io.h0000600000175000017500000000640210023147414016410 0ustar duclouxducloux00000000000000/* This is io.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef IO_H /* guarantee single inclusion */ #define IO_H #include "globals.h" namespace io { using namespace globals; }; /******** type definitions **************************************************/ namespace io { class String; /* style tags for i/o */ struct Default{}; struct GAP {}; struct LaTeX {}; struct Pretty {}; struct Terse {}; struct TeX {}; }; /******** constants **********************************************************/ namespace io { const Ulong LINESIZE = 79; const Ulong HALFLINESIZE = 39; }; /******** function declarations **********************************************/ namespace io { int alphabeticDigits(Ulong c, Ulong b); String& append(String& l, const char c); String& append(String& l, const char *s); String& append(String& l1, const String& l2); String& append(String& l, const Ulong& n); String& append(String& l, const long& m); String& append(String& l, const unsigned& n); String& append(String& l, const int& n); String& append(String& l, const int *v, const Ulong& n); int digits(Ulong c, Ulong b); String& erase(String& l, const Ulong& n); void foldLine(FILE* file, const String& str, const Ulong& ls, const Ulong& h, const char* hyphens); char* getInput(FILE *inputfile, String& buf, Ulong len = 0); String& pad(String& l, const Ulong& n); void print(FILE* file, const char * str); /* inlined */ void print(FILE* file, const String& str); /* inlined */ void print(FILE* file, const int *const& v, const Ulong& n); void printFile(FILE* file, const char *name); void printFile(FILE* file, const char *name, const char *dir_name); String& reset(String& l); String& setString(String& l, const String& s, const Ulong &first, const Ulong& r); Ulong skipSpaces(const String& l, Ulong p); }; /******** type definitions **************************************************/ #include "list.h" #include "memory.h" namespace io { using namespace list; using namespace memory; }; namespace io { class String:public List { private: public: /* constructors and destructors */ String():List() {}; explicit String(const Ulong& n):List(n+1) {setSizeValue(1);} explicit String(const int& n):List(n+1) {setSizeValue(1);} String(const char* const str):List(strlen(str)+1) {setData(str,strlen(str)+1);} ~String(); /* modifiers */ void setLength(const Ulong& n); /* inlined */ /* accessors */ bool isDefined() const; /* inlined */ Ulong length() const; /* inlined */ /* static member function */ static const String& undefined(); }; }; /******** Inline definitions ***********************************************/ namespace io { inline void print(FILE *file, const char* str) {fprintf(file,"%s",str);} inline void print(FILE *file, const String& str) {fprintf(file,"%s",str.ptr());} inline void String::setLength(const Ulong& n) {setSize(n+1);} inline bool String::isDefined() const {return size();} inline Ulong String::length() const {return size()-1;} }; #endif positivity_final/messages/0000700000175000017500000000000010256224747017450 5ustar duclouxducloux00000000000000positivity_final/messages/author.help0000600000175000017500000000015607576410316021630 0ustar duclouxducloux00000000000000 The command "author" types a message about the author of this program, his affiliation and current address. positivity_final/messages/cr.help0000600000175000017500000000010407576410316020723 0ustar duclouxducloux00000000000000 Typing return re-executes the last command (except in help mode). positivity_final/messages/q.help0000600000175000017500000000014310010407521020537 0ustar duclouxducloux00000000000000 The command "q" is used to exit special modes, such as help mode. Type "qq" to exit the program. positivity_final/messages/author.mess0000600000175000017500000000167507732523160021652 0ustar duclouxducloux00000000000000 This program was written by Fokko du Cloux, Institut Girard Desargues (UMR CNRS 5028), Universite Lyon-I. It is made available under the GNU General Public License (see file main.c for full copyright notice.) The program was developed under Linux, using only free software, mostly from GNU. The author wishes to express his appreciation to all the people who have contributed to give these systems to the world. Current address : Institut Girard Desargues Universite Lyon-I, bat. Jean Braconnier 69622 Villeurbanne Cedex FRANCE ducloux@igd.univ-lyon1.fr http://igd.univ-lyon1.fr/home/ducloux/coxeter.html A large part of the development work on this program was done while the author was visiting the Centre de Recherches Mathematiques, Montreal, and the University of British Columbia, Vancouver. Many thanks to both institutions for their hospitality and in particular to Bill Casselman who was the driving force in arranging both visits. positivity_final/messages/type.help0000600000175000017500000000024107576410316021302 0ustar duclouxducloux00000000000000 The command "type" allows the user to change the type of the current group (thus restarting the program.) He is then also automatically prompted for the rank. positivity_final/messages/qq.help0000600000175000017500000000022307576410316020742 0ustar duclouxducloux00000000000000 Typing "qq" exits the program without further ado (except in help mode). Typing "q" exits the current mode (in special modes such as help mode). positivity_final/messages/help.help0000600000175000017500000000036210010407513021233 0ustar duclouxducloux00000000000000 The "help" command puts the program in help mode. It prints a message describing the mode it is currently in, and allows the user to type any legal command name, printing a help message for that command. To quit help mode, simply type "q". positivity_final/messages/type_m.help0000600000175000017500000000057507576410316021630 0ustar duclouxducloux00000000000000 You are currently in mode type_m. This is an artificial mode, intended for that brief span in time where the type is set, but not the rank. If you got stuck in this mode, it's because you answered to the Rank: prompt with a carriage return. To continue, you should simply say "rank" again to set the rank for the current type, or say "type" if you also want to reset the type. positivity_final/messages/rank.help0000600000175000017500000000076107576410316021263 0ustar duclouxducloux00000000000000 The "rank" command may be used to change the rank while keeping the type. This makes for a bit nicer interaction. If we are in one of the standard families A-I, a-g, the meaning is obvious (the rank given will be checked to be meaningful); If we are in types X/x or Y/y, giving l as the rank means that the first l elements of the first l lines of the file are used as the Coxeter matrix (so that a single file can be used for a family of groups.) An error occurs if the file is not big enough. positivity_final/messages/kl_m.help0000600000175000017500000000071107576410316021245 0ustar duclouxducloux00000000000000 The program is currently in kl mode. This is the mode in which Kazhdan- Lusztig polynomials are computed. Contrary to prior versions of the program, no preliminary tables whatsoever are computed aforehand. At each point in time, tables for the bruhat order and the actions of the generators on an initial subset of the group are maintained, and grown according to the requests of the user. In this demo version, the commands available in this mode are : positivity_final/messages/cell.help0000600000175000017500000000320307576410316021241 0ustar duclouxducloux00000000000000 The command "cell" is the main commannd of this demo version. It prompts for an element y of the current group, which should be given in the form of a string of generators. It then attempts to construct the corresponding "kl context" (the schubert cell [e,y], and the action of the various generators on it), and to compute the k-l polynomials P_{x,y} with x "extremal" w.r.t. y. The major obstacle to this computation is lack of enough memory. In case of success, the program outputs the essential data about the cell, on a file chosen by the user, or stdout by default. This includes the list of extremal k-l polynomials, and the printout of the various layers of the singular locus of the corresponding schubert cell, as described by Mark Goresky in "Tables of Kazhdan-Lusztig polynomials", http://www.math.ias.edu/~goresky (of course we don't know how to construct such a schubert cell for general coxeter groups, but it is likely that in all cases there will exist a geometry for which such an interpretation holds.) To be precise, we output the maximal elements in the sets of elements having a given (non-trivial) k-l polynomial. This should correspond to the supports of the various layers of (rational) singularity. A * in the output corresponds to polynomials for which the degree is as big as it can be (in other words, for which the so-called mu-coefficient is non-zero.) Finally, we print the betti numbers and intersection homology Betti numbers (the latter are readily expressed in terms of k-l polynomials) of the corresponding schubert cell. In case of failure, the program tries to explain why : lack of memory? If so, at which stage? positivity_final/messages/wrongtype.mess0000600000175000017500000000046407576410316022405 0ustar duclouxducloux00000000000000 The types allowed are : A,B,C,D,E,F,G,H,I for the finite Coxeter groups (here I stands for the dihedral groups) a,b,c,d,e,f,g for the affine Weyl groups X,x for arbitrary Coxeter groups, where the matrix is read from a file, and Y,y if the matrix is read interactively. Carriage return will abort. positivity_final/messages/empty_m.help10000600000175000017500000000057607576410316022067 0ustar duclouxducloux00000000000000 This help message is intended to get new users started with the program. We refer the user to the INTRO file for a more detailed description of the capabilities and limitations of the program, and for comments about the various algorithms that have been used. The program works with a command interface. The list of available commands in the main program mode is the following : positivity_final/messages/schubert_m.help0000600000175000017500000000062007576410316022455 0ustar duclouxducloux00000000000000 The program is currently in schubert mode. This is the mode in which schubert cells are constructed, according to the algorithm described in the introduction. Various functions for probing the poset structure of the corresponding cell should eventually be available in this mode; in this demo version, it is simply used to set up the context for the computation of the kazhdan-lusztig polynomials. positivity_final/messages/show.help0000600000175000017500000000115107626114231021273 0ustar duclouxducloux00000000000000 The command show takes as input two elements x and y in the group, and prints out the various ingredients in the recursion formula for P_{x,y}. This opens up the computations a little bit, and makes it easier to understand what's going on. It's also very nice for the purpose of following a computation step by step, say for debugging purposes. The generator is entered as "l" or "r" (depending on which side you want it to act) followed by the current input symbol of your generator; if you enter an empty string, the default descent generator is used. To find out the descent set of your element, use "descent". positivity_final/messages/resize.err0000600000175000017500000000025007576410316021462 0ustar duclouxducloux00000000000000 An attempt was made to resize a block in a fixed-size memory zone. This means a bug in the program, unless you added some code of your own. Please notify the author. positivity_final/messages/empty_m.help20000600000175000017500000000342607772730456022075 0ustar duclouxducloux00000000000000 Command completion is enforced if the input string has a unique nonambiguous completion (except in cases where this seemed inappropriate.) Note that the program starts up in the so-called "empty" mode (the mode it is in before type and rank are defined); most of the above commands will be available only after you have entered type and rank. Even the help information about them is initially unavailable, but will become available as soon as you have entered a valid type and rank. You can always type "help" whenever you have the prompt. This puts you in help mode, where typing a command results in a brief description of its workings. Some commands put the program in a special "mode"; this is usually apparent from the fact that the prompt changes. The idea is to avoid polluting the global command space with rarely used names (or worse, with names that create annoyance when typed by accident), and/or to allow some command names to behave differently under certain circumstances. The typical example of this is help mode. The modes function as a pushdown stack : on exiting a mode we are put back in the mode where we came from. A word about ranks. In principle the implementation of Coxeter groups allows ranks up to 255, and coxeter matrix entries up to 32763 (or infinity). However, for the convenience of the programmer and for efficiency reasons, currently we have restricted the program to ranks at most equal to half the bit-size of an unsigned long on your computer (this is usually 16 on a 32-bit computer, and 32 on a 64-bit one.) Particularly in view of the coming migration to 64 bits, this seems to cover the main cases of interest. Also, if the program is unable to construct the full minimal root table for lack of memory, it will quit. Again, this is no limitation in practice. positivity_final/messages/silent.help0000600000175000017500000000036407576410316021625 0ustar duclouxducloux00000000000000 The command "silent" turns off status reports during computations (this is the default). When the computation takes more than a few seconds, it is usually more pleasant to monitor what's going on --- to turn on status reports, say "verbose". positivity_final/messages/verbose.help0000600000175000017500000000016707576410316021775 0ustar duclouxducloux00000000000000 The command "verbose" turns on status reports during computations. If you want to turn them off again, say "silent". positivity_final/messages/general_m.help0000600000175000017500000000030407576410316022252 0ustar duclouxducloux00000000000000 You are currently in mode general_m. This means that the type and rank of our current Coxeter group have been set successfully; only operations on the Coxeter matrix are possible at this point. positivity_final/messages/matrix.help0000600000175000017500000000033407576410316021630 0ustar duclouxducloux00000000000000 The command "matrix" prints out the Coxeter matrix of the current group. This is useful to see if interactive or file input had the desired effect, or to check the enumeration of the generators for the standard types. positivity_final/messages/main.help10000600000175000017500000000015507576410316021332 0ustar duclouxducloux00000000000000 You are currently in the main mode of the program. The commands available in this mode are the following : positivity_final/messages/interface/0000700000175000017500000000000010006513234021371 5ustar duclouxducloux00000000000000positivity_final/messages/interface/alphabetic.help0000600000175000017500000000044707775624246024377 0ustar duclouxducloux00000000000000 The "alphabetic" command in general interface mode activates the standard alphabetical symbols for input and output : the symbols are the alphabetical sequence "a", "b", ... , "z", "aa", ...; the prefix and postfix are empty, and the separator is empty unless the rank is > 26, when it is "." positivity_final/messages/interface/bourbaki.help0000600000175000017500000000103307732526762024066 0ustar duclouxducloux00000000000000 The "bourbaki" command sets i/o conventions to Bourbaki. This means that the default ordering of the generators in types B and D is reversed from our usual choice; nothing is changed for the other types. In order to have output which is not too confusing, and which is consistent with other programs that adopt Bourbaki conventions, such as GAP, we also permute the generator symbols; usually they are attributed in the natural ordering of the vertices, so the effect is an increasing labelling of the generators in the new enumeration. positivity_final/messages/interface/decimal.help0000600000175000017500000000040607775625453023675 0ustar duclouxducloux00000000000000 The "decimal" command in general interface mode activates the standard decimal symbols for input and output : the symbols are the decimal sequence "1", "2"; the prefix and postfix are empty, and the separator is empty unless the rank is > 9, when it is "." positivity_final/messages/interface/gap.help0000600000175000017500000000121407732534765023042 0ustar duclouxducloux00000000000000 The "gap" command sets i/o conventions to GAP style. This means first of all that Bourbaki conventions are adopted (see the help message for the "bourbaki" command.) Futher, decimal generator symbols are set, and prefix, separator, and postfix are set respectively to "[", ",", "]", so that for instance an element denoted 12321 in our standard notation becomes [1,2,3,2,1]. This applies to both input and output. Furthermore, all output to files is done in such a way that the corresponding files are directly legible by GAP3, and contain legal definitions of GAP objects. This sets up a rudimentary communication protocol between GAP and Coxeter. positivity_final/messages/interface/hexadecimal.help0000600000175000017500000000044607775624336024546 0ustar duclouxducloux00000000000000 The "hexadecimal" command in general interface mode activates the standard hexadecimal symbols for input and output : the symbols are the hexadecimal sequence "1", "2", ... , "f", "10", ...; the prefix and postfix are empty, and the separator is empty unless the rank is > 15, when it is "." positivity_final/messages/interface/in/0000700000175000017500000000000010006741505022003 5ustar duclouxducloux00000000000000positivity_final/messages/interface/in/bourbaki.help0000600000175000017500000000103507732527122024465 0ustar duclouxducloux00000000000000 The "bourbaki" command sets input conventions to Bourbaki. This means that the default ordering of the generators in types B and D is reversed from our usual choice; nothing is changed for the other types. In order to have output which is not too confusing, and which is consistent with other programs that adopt Bourbaki conventions, such as GAP, we also permute the generator symbols; usually they are attributed in the natural ordering of the vertices, so the effect is an increasing labelling of the generators in the new enumeration. positivity_final/messages/interface/in/gap.help0000600000175000017500000000057307732535051023444 0ustar duclouxducloux00000000000000 The "gap" command sets input conventions to GAP style. This means first of all that Bourbaki conventions are adopted (see the help message for the "bourbaki" command.) Futher, decimal generator symbols are set, and prefix, separator, and postfix are set respectively to "[", ",", "]", so that for instance an element denoted 12321 in our standard notation becomes [1,2,3,2,1]. positivity_final/messages/interface/in/postfix.help0000600000175000017500000000037207772211515024366 0ustar duclouxducloux00000000000000 The postfix command allows you to reset the input postfix. The postfix may be an arbitrary string, including the empty string. If it is non-empty, it must be different from all other input symbols. This is checked at the end of your modifications. positivity_final/messages/interface/in/prefix.help0000600000175000017500000000036707731055356024177 0ustar duclouxducloux00000000000000 The prefix command allows you to reset the input prefix. The prefix may be an arbitrary string, including the empty string. If it is non-empty, it must be different from all other input symbols. This is checked at the end of your modifications. positivity_final/messages/interface/in/separator.help0000600000175000017500000000112607772434365024702 0ustar duclouxducloux00000000000000 The separator command allows you to reset the input separator. The separator may be an arbitrary string, including the empty string, but may not start with white space. In addition, all the strings of the input interface must be distinct. The empty string is likely to cause problems when the generator symbols have embeddings (e.g. if 1, 2, and 12 are all three input symbols, then with empty separator the string 12 will always be parsed as the single generator 12, never as 1 times 2.) However, white space in input will always act as a separator, so you could still enter 1 2 in that case. positivity_final/messages/interface/in/symbol.help0000600000175000017500000000045607772435370024211 0ustar duclouxducloux00000000000000 The symbol command allows you to reset an input symbol. Input symbols may be arbitrary non-empty strings, except that they have to be distinct from each other and from the other input symbols, and that they are not allowed to begin with whitespace. This is checked at the end of your modifications. positivity_final/messages/interface/in/default.help0000600000175000017500000000031007735033573024313 0ustar duclouxducloux00000000000000 The "default" command resets input conventions to their default values. This means that decimal symbols are used, no pre- or postfix, and that the separator "." is used only when the rank is >= 10. positivity_final/messages/interface/in/terse.help0000600000175000017500000000046507735022673024023 0ustar duclouxducloux00000000000000 The "terse" command sets input conventions to terse style. This style is meant for i/o that is easily parsed by computer. Decimal generator symbols are adopted, with GAP-style representation of words. The ordering of the generators is left untouched, and can be set separately by the user, if so desired. positivity_final/messages/interface/in/decimal.help0000600000175000017500000000031007775624514024272 0ustar duclouxducloux00000000000000 The "decimal" command in input mode sets the input symbols to the decimal sequence "1", "2", ... It doesn't change prefix, postfix or separator (you can of course change these yourself separately.) positivity_final/messages/interface/in/alphabetic.help0000600000175000017500000000034007775624623024774 0ustar duclouxducloux00000000000000 The "alphabetic" command in input mode sets the input symbols to the alphabetic sequence "a", "b", ... , "z", "aa", ... It doesn't change prefix, postfix or separator (you can of course change these yourself separately.) positivity_final/messages/interface/in/permutation.help0000600000175000017500000000045610006735056025237 0ustar duclouxducloux00000000000000 The "permutation" command in input mode activates input in permutation form; this means that group elements are written as permutations of the hexadecimal symbols {0,...,n}, where n is the rank. This is more compact than the standard notation, and very useful for interaction with other programs. positivity_final/messages/interface/in/hexadecimal.help0000600000175000017500000000034207775624706025150 0ustar duclouxducloux00000000000000 The "hexadecimal" command in input mode sets the input symbols to the hexadecimal sequence "1", "2", ... , "f", "10", ... It doesn't change prefix, postfix or separator (you can of course change these yourself separately.) positivity_final/messages/interface/in.help0000600000175000017500000000057107730767276022711 0ustar duclouxducloux00000000000000 The "in" command will put you in the mode for resetting the input interface. As always, this mode is exited with "q"; on exit, the program will check if your new choices are consistent with the remaining old choices (consistency of the new choices will aready have been checked). If a problem is found, it will put you in "in" mode again so that you can review your choices. positivity_final/messages/interface/in_m.help10000600000175000017500000000062007731046232023260 0ustar duclouxducloux00000000000000 You are currently in the "in" mode of the interface environment; this is a small mode intended for the resetting of the parameters which govern the input of group elements into the program. On exit, your settings will be checked for consistency with the remaining old settings; in particular, no non-empty input symbols may be used in two different meanings. Commands available in this mode are : positivity_final/messages/interface/in_m.help20000600000175000017500000000011207731046262023260 0ustar duclouxducloux00000000000000 Type the corresponding command name for more details on each operation. positivity_final/messages/interface/ordering.help0000600000175000017500000000123007732240502024061 0ustar duclouxducloux00000000000000 The command "ordering" allows you to change the ordering of the generators. This does not change the way the program deals with the group internally; it only affects the output, and the definition of ShortLex normal forms, for instance. One should not confuse the ordering of the generators, and the symbols which are attached to them (this can be a little bit confusing when the symbols themselves are labels like "1", "2", etc.) We have taken the approach that symbols are attached to actual generators; changing the ordering does not affect the correspondence. This makes it easy, for instance, to see how normal forms change when the ordering is changed. positivity_final/messages/interface/out/0000700000175000017500000000000010006741505022204 5ustar duclouxducloux00000000000000positivity_final/messages/interface/out/bourbaki.help0000600000175000017500000000103707732527153024674 0ustar duclouxducloux00000000000000 The "bourbaki" command sets output conventions to Bourbaki. This means that the default ordering of the generators in types B and D is reversed from our usual choice; nothing is changed for the other types. In order to have output which is not too confusing, and which is consistent with other programs that adopt Bourbaki conventions, such as GAP, we also permute the generator symbols; usually they are attributed in the natural ordering of the vertices, so the effect is an increasing labelling of the generators in the new enumeration. positivity_final/messages/interface/out/gap.help0000600000175000017500000000115007732535154023641 0ustar duclouxducloux00000000000000 The "gap" command sets output conventions to GAP style. This means first of all that Bourbaki conventions are adopted (see the help message for the "bourbaki" command.) Futher, decimal generator symbols are set, and prefix, separator, and postfix are set respectively to "[", ",", "]", so that for instance an element denoted 12321 in our standard notation becomes [1,2,3,2,1]. Furthermore, all output to files is done in such a way that the corresponding files are directly legible by GAP3, and contain legal definitions of GAP objects. This sets up a rudimentary communication protocol between GAP and Coxeter. positivity_final/messages/interface/out/postfix.help0000600000175000017500000000014007731055221024553 0ustar duclouxducloux00000000000000 The postfix command allows you to reset the output postfix. This may be an arbitrary string. positivity_final/messages/interface/out/prefix.help0000600000175000017500000000013607731055252024365 0ustar duclouxducloux00000000000000 The prefix command allows you to reset the output prefix. This may be an arbitrary string. positivity_final/messages/interface/out/separator.help0000600000175000017500000000014407731055310025062 0ustar duclouxducloux00000000000000 The separator command allows you to reset the output separator. This may be an arbitrary string. positivity_final/messages/interface/out/symbol.help0000600000175000017500000000015607731047345024403 0ustar duclouxducloux00000000000000 The symbol command allows you to reset an output symbol. Output symbols may be arbitrary non-empty strings. positivity_final/messages/interface/out/default.help0000600000175000017500000000050507772636212024522 0ustar duclouxducloux00000000000000 The "default" command resets output conventions to their default values. This means that decimal symbols are used, no pre- or postfix, and that the separator "." is used only when the rank is >= 10. The ordering of the generators also reverts to the default ordering. The style for the output files is the Pretty style. positivity_final/messages/interface/out/terse.help0000600000175000017500000000122107735022725024211 0ustar duclouxducloux00000000000000 The "terse" command sets output conventions to terse style. This style is meant to produce output that is easily parsed by computer. Decimal generator symbols are adopted, with GAP-style representation of words, and a string- representation of polynomials is adopted as well, without an explicit indeterminate. The ordering of the generators is left untouched, and can be set separately by the user, if so desired. Output files in the terse style usually contain a number of comment-lines, starting with the # symbol, which explain the contents and the format of the file; that way, the file should be usable without having to look at this help message. positivity_final/messages/interface/out/hexadecimal.help0000600000175000017500000000034407775624740025351 0ustar duclouxducloux00000000000000 The "hexadecimal" command in output mode sets the output symbols to the hexadecimal sequence "1", "2", ... , "f", "10", ... It doesn't change prefix, postfix or separator (you can of course change these yourself separately.) positivity_final/messages/interface/out/permutation.help0000600000175000017500000000046010006735024025426 0ustar duclouxducloux00000000000000 The "permutation" command in output mode activates output in permutation form; this means that group elements are written as permutations of the hexadecimal symbols {0,...,n}, where n is the rank. This is more compact than the standard notation, and very useful for interaction with other programs. positivity_final/messages/interface/out/alphabetic.help0000600000175000017500000000034207775625000025165 0ustar duclouxducloux00000000000000 The "alphabetic" command in output mode sets the output symbols to the alphabetic sequence "a", "b", ... , "z", "aa", ... It doesn't change prefix, postfix or separator (you can of course change these yourself separately.) positivity_final/messages/interface/out/decimal.help0000600000175000017500000000031207775625036024475 0ustar duclouxducloux00000000000000 The "decimal" command in output mode sets the output symbols to the decimal sequence "1", "2", ... It doesn't change prefix, postfix or separator (you can of course change these yourself separately.) positivity_final/messages/interface/out.help0000600000175000017500000000034307730767414023101 0ustar duclouxducloux00000000000000 The "out" command will put you in the mode for resetting the input interface. As always, this mode is exited with "q". Since output symbols may be completely arbitrary strings, no consistency check is necessary here on exit. positivity_final/messages/interface/out_m.help10000600000175000017500000000051207731046467023473 0ustar duclouxducloux00000000000000 You are currently in the "out" mode of the interface environment; this is a small mode intended for the resetting of the parameters which govern the output of group elements into the program. Since arbitrary strings are allowed for all output parameters, no consistency check is necessary Commands available in this mode are : positivity_final/messages/interface/out_m.help20000600000175000017500000000011207731046315023460 0ustar duclouxducloux00000000000000 Type the corresponding command name for more details on each operation. positivity_final/messages/interface/default.help0000600000175000017500000000037207735033511023705 0ustar duclouxducloux00000000000000 The "default" command resets i/o conventions to their default values. This means that decimal symbols are used, no pre- or postfix, and that the separator "." is used only when the rank is >= 10. The style for the output files is the Pretty style. positivity_final/messages/interface/terse.help0000600000175000017500000000121607735022507023404 0ustar duclouxducloux00000000000000 The "terse" command sets i/o conventions to terse style. This style is meant to produce output that is easily parsed by computer. Decimal generator symbols are adopted, with GAP-style representation of words, and a string- representation of polynomials is adopted as well, without an explicit indeterminate. The ordering of the generators is left untouched, and can be set separately by the user, if so desired. Output files in the terse style usually contain a number of comment-lines, starting with the # symbol, which explain the contents and the format of the file; that way, the file should be usable without having to look at this help message. positivity_final/messages/interface/abort.help0000600000175000017500000000021307732336635023374 0ustar duclouxducloux00000000000000 The "abort" command quits input modification mode without changing the interface. Use this when you get confused or wish to start again. positivity_final/messages/interface/permutation.help0000600000175000017500000000046510006400262024615 0ustar duclouxducloux00000000000000 The "permutation" command in general interface mode activates i/o in permutation form; this means that group elements are written as permutations of the hexadecimal symbols {0,...,n}, where n is the rank. This is more compact than the standard notation, and very useful for interaction with other programs. positivity_final/messages/interface_m.help20000600000175000017500000000011207576410316022654 0ustar duclouxducloux00000000000000 Type the corresponding command name for more details on each operation. positivity_final/messages/interface.help0000600000175000017500000000072307760124626022267 0ustar duclouxducloux00000000000000 The "interface" command puts the program in interface mode. This allows you to enter various commands to change the parameters which govern the input/output functions : you can change the symbols representing the generators, prefix, postfix and generator both for input and output (notice that it can be rather useful to have different symbols for input and output), and the ordering of the generators. The commands available in interface mode are the following : positivity_final/messages/default.help0000600000175000017500000000007107576410316021746 0ustar duclouxducloux00000000000000 Sorry, no help information available for this command. positivity_final/messages/main.help20000600000175000017500000000012707576410316021332 0ustar duclouxducloux00000000000000 Type the command name in help mode for more information. Type "q" to exit help mode. positivity_final/messages/special.defhelp0000600000175000017500000000031707576410316022424 0ustar duclouxducloux00000000000000 The "special" command executes the function special_f, defined in the file special.c. The default value is to print an "unimplemented" message; you can define an arbitrary action by editing the function. positivity_final/messages/lrcwgraphs.help0000600000175000017500000000106110000202500022440 0ustar duclouxducloux00000000000000 The "lrcwgraphs" command prints out the W-graphs of the two-sided cells in the group. The cells are sorted in ShortLex order (for the current ordering of the generators); this is the order in which they are output by the "lrcells" command. In the default output mode, the graphs are numbered by the number of the corresponding cell in the above ordering; they are output in the default format for W-graphs (one line per node, starting wtih the descent set, and followed by the edge-list). See the help message for the "lrwgraph" command for more details. positivity_final/messages/neg_coeff.err0000600000175000017500000000111407614015471022070 0ustar duclouxducloux00000000000000 Congratulations !! You just found a negative coefficient in a Kazhdan-Lusztig polynomial. If this is not due to a bug in the program, it is a counter-example to a longstanding conjecture, and should definitely be published. Be aware that Kazhdan-Lusztig polynomials have been shown to have positive coefficients for all finite Coxeter groups (computationally in the case of H3 and H4), and for all Weyl groups of Kac-Moody Lie algebras. So if your group is one of these, there is definitely a bug in the program. Please notify the author (ducloux@desargues.univ-lyon1.fr) either way. positivity_final/messages/schubert.help0000600000175000017500000000165407626156603022153 0ustar duclouxducloux00000000000000 The schubert command prints out data for a schubert closure in the group (this was called "cell" in Coxeter2). This is essentially the information contained in the element c_y of the k-l basis of the Hecke algebra. For a given y, the command prints out the coatoms of y, then the values of P_{x,y} for x <= y extremal w.r.t. y (this gives in particular all the P_{x,y} that come up in c_y). Then we print out information on the singular locus of the Schubert variety (when this exists) : this means that for each polynomial p != 1, we print out the maximal elements of the set of x <= y s.t. P_{x,y} = p (these will correspond to the irreducible components of the strata in the "equi-kl" stratification of the Schubert variety.) This is the information contained in the files produced by Goresky. The command "klbasis" will produce the actual c_y in GAP-format (be aware that this can get _huge_, and will most likely be hard to use.) positivity_final/messages/pol.help0000600000175000017500000000053707774217276021135 0ustar duclouxducloux00000000000000 The pol command prints out a single polynomial P_{x,y}. You should enter x as response to "first", y as response to "second". It is looked up in the table if available, computed otherwise. As few k-l polynomials are computed as possible, but all computed polynomials are remembered. If you would like more detail about the computation, try "show". positivity_final/messages/descent.help0000600000175000017500000000015707625422564021757 0ustar duclouxducloux00000000000000 The descent command prints out the left and right descent sets, in the current output format for generators. positivity_final/messages/permutation.mess0000600000175000017500000000007610006377202022701 0ustar duclouxducloux00000000000000 sorry, permutation representation is allowed only in type A positivity_final/messages/compute.help0000600000175000017500000000207707771356430022011 0ustar duclouxducloux00000000000000 The compute command prints out the normal form of an element. Moreover, if the group has been classified as a SmallCoxGroup (this means that it is finite, and that its order fits into an unsigned long), a representation of the element as a single number (preceded by a # sign) is printed. Otherwise, if the element lies in the current context for k-l computations, its number in the context (preceded by a % sign) is printed. These numbers are convenient as shorthand notations and may be used in input. Note that the # number, when defined, is always the same; the % number, on the other hand, may be session-dependent (it depends on how the context has been built up.) It is even possible that the program decides to reorder the context during a computation (this will happen only rarely, for very big computations;) we will try to remember to print a warning like "warning : % numbers may have changed" every time this occurs. Then you need to use "compute" again to discover the new % number of your element. Type "input" in help mode for a full description of the input rules. positivity_final/messages/showmu.help0000600000175000017500000000115207673273402021646 0ustar duclouxducloux00000000000000 The command show takes as input two elements x and y in the group, and prints out the various ingredients in the recursion formula for mu(x,y). The algorithm tries to push the computation down until a "double extremal" situation is reached, where x is extremal w.r.t. all ys, s in R(y) (using the analysis of "star-operations" in the k-l paper.) The generator is entered as "l" or "r" (depending on which side you want it to act) followed by the current input symbol of your generator; if you enter an empty string, the default descent generator is used. To find out the descent set of your element, use "descent". positivity_final/messages/mu.help0000600000175000017500000000055607673270741020757 0ustar duclouxducloux00000000000000 The command "mu" prints out the mu-coefficient mu(x,y) for two given elements x and y in the group; x should be entered in response to "first", y in response to "second". The result is looked up in the table if available, computed otherwise. The computation of k-l polynomials is avoided as much as possible. To see the details of the computation, try "showmu". positivity_final/messages/lcellorder.help0000600000175000017500000000153407733037220022450 0ustar duclouxducloux00000000000000 The "lcellorder" command prints out the natural ordering on the set of all left cells in the group. Currently it works only for (some) finite groups; more precisely, it will work only if the full mu-table of the group could be computed. The limit for this on a decent-sized workstation nowadays (2003) seems to lie around E7, inclusive if you're lucky, barely exclusive if you're not. For finite Weyl groups, there is a 1-1 correspondence between left cells and primitive ideals in the enveloping algebra with trivial infinitesimal character; in this correspondence, the left cell ordering corresponds to the inclusion ordering among ideals. What is printed is the Hasse diagram of the ordering : for each cell number, we print the numbers of the cells immediately above the given one (recall that the identity is the greatest element in the cell ordering.)positivity_final/messages/extremals.help0000600000175000017500000000027110000745713022314 0ustar duclouxducloux00000000000000 The "extremals" command prints out the list of extremal elements x <= y, together with their corresponding k-l polynomials (this list appears also as part of the "schubert" command.) positivity_final/messages/interface_m.help10000600000175000017500000000116407732524263022664 0ustar duclouxducloux00000000000000 You are currently in interface mode; this is a "floating" mode meant for changing either the ordering of the generators, or the appearance of the output. You exit this mode by typing "q"; this will put you back where you were previously. Changes to the interface only affect input-output operations, and don't change anything in the internal representation of the group. Therefore they can be made at any time without penalty; all your previous computations will be preserved. All changes are relative to the current group only; every new group starts up with the default interface. Commands available in this mode are : positivity_final/messages/wgraph.mess0000600000175000017500000000032307734322733021632 0ustar duclouxducloux00000000000000 warning : group context is not complete. The output of the wgraph command will most likely not be a true W-graph. If the group is finite, you can (try to) complete the context using the "fullcontext" command. positivity_final/messages/duflo.mess0000600000175000017500000000010607733061227021447 0ustar duclouxducloux00000000000000 sorry, command "duflo" is currently defined only for finite groups. positivity_final/messages/coatoms.help0000600000175000017500000000075007775561566022012 0ustar duclouxducloux00000000000000 The "coatoms" command prints out the coatoms of a given element x in the group. Recall that these are the z < x which are of length one less than x; so the set of coatoms is empty iff x is the identity element (in terms of posets, these are the coatoms of the poset [e,x], for the Bruhat ordering.) It is known that the number of coatoms is at least equal to the cardinality of the support of x. Finding good upper bounds (when such exist) for any given group is much more difficult. positivity_final/messages/duflo.help0000600000175000017500000000065007734011221021422 0ustar duclouxducloux00000000000000 The "duflo" command prints out the Duflo (or distinguished) involutions in the group. These are the unique elements in each left Kazhdan-Lusztig cell for which the number l(d)-2*deg(P_{e,d}) is minimal; it turns out that they are involutions. They are output in the same order as the one used for left cells, i.e. by shortlex order of the shortlex-smallest element in the cell, for the current ordering of the generators. positivity_final/messages/fullcontext.mess0000600000175000017500000000007307734010357022707 0ustar duclouxducloux00000000000000 command "fullcontext" is defined only for finite groups. positivity_final/messages/slocus.help0000600000175000017500000000054210001214302021603 0ustar duclouxducloux00000000000000 Given an element y in the group, the "slocus" command prints out the maximal elements of the set of x <= y s.t. P_{x,y} != 1 (in the case of Weyl groups, this is known to be a decreasing subset of [e,y]). These correspond to the irreducible components of the (rational) singular locus of the Schubert variety defined by y (in the case of Weyl groups). positivity_final/messages/lcells.help0000600000175000017500000000055607733033546021611 0ustar duclouxducloux00000000000000 The "lcells" command prints out the full list of left cells of the group, with the corresponding W-graphs. The numbering of the cells in all the cell commands is consistent; the lists that are printed are always printed in the same ordering (corresponding to the shortlex ordering of the first element in the cell, in the standard enumeration of the generators.) positivity_final/messages/lcwgraphs.help0000600000175000017500000000104710000202340022264 0ustar duclouxducloux00000000000000 The "lcwgraphs" command prints out the W-graphs of the left cells in the group. The cells are sorted in ShortLex order (for the current ordering of the generators); this is the order in which they are output by the "lcells" command. In the default output mode, the graphs are numbered by the number of the corresponding cell in the above ordering; they are output in the default format for W-graphs (one line per node, starting wtih the descent set, and followed by the edge-list). See the help message for the "lwgraph" command for more details. positivity_final/messages/rcwgraph.help0000600000175000017500000000136107777546251022155 0ustar duclouxducloux00000000000000 The "rcwgraphs" command prints out the W-graphs of the right cells in the group. The cells are sorted in ShortLex order (for the current ordering of the generators); this is the order in which they are output by the "rcells" command. In the default output mode, the W-graphs in the following format : first we output the descents sets for each node in each cell, one line per cell; then, for each of the cells, in increasing order, we output one line per vertex of the cell, containing a list of pairs (e;mu), one for each edge originating from that vertex, where e is the extremity of the edge, and mu is the corresponding mu-coefficient. The file-output formats will include comments in their files explaining the output format which is used. positivity_final/messages/lcells.mess0000600000175000017500000000010707734323457021624 0ustar duclouxducloux00000000000000 sorry, command "lcells" is currently defined only for finite groups. positivity_final/messages/wgraph.help0000600000175000017500000000112407733040075021606 0ustar duclouxducloux00000000000000 The "wgraph" command prints out the W-graph of the group, numbered as always in the ordering described in the help message for "lcells". For each node in the graph, we print out the edges in the edges in the graph originating from that node, together with the corresponding mu-coefficient. This function will give a correct answer only if the full mu-table for the group has been computed. Because this is of interest for further investigations, we allow the command to be called also for infinite, or partially filled, groups, even though the result is not then an actual W-graph in general. positivity_final/messages/uneq/0000700000175000017500000000000010006766726020421 5ustar duclouxducloux00000000000000positivity_final/messages/uneq/lcells.help0000600000175000017500000000037207743207656022563 0ustar duclouxducloux00000000000000 The command "lcells" prints out the left cells in the group, for the current choice of parameters. The cells are sorted in ShortLex order (for the current ordering of the generators), and printed in the ShortLex order of their smallest element. positivity_final/messages/uneq/lcells.mess0000600000175000017500000000010707743207506022570 0ustar duclouxducloux00000000000000 sorry, command "lcells" is currently defined only for finite groups. positivity_final/messages/uneq/pol.help0000600000175000017500000000043510006745220022053 0ustar duclouxducloux00000000000000 The pol command prints out a single polynomial P_{x,y}. You should enter x as response to "first", y as response to "second". It is looked up in the table if available, computed otherwise. As few k-l polynomials are computed as possible, but all computed polynomials are remembered. positivity_final/messages/uneq/lcorder.mess0000600000175000017500000000011010000214704022710 0ustar duclouxducloux00000000000000 sorry, command "lcorder" is currently defined only for finite groups. positivity_final/messages/uneq/mu.help0000600000175000017500000000104110006766610021702 0ustar duclouxducloux00000000000000 The command "mu" prints out the mu-coefficient mu(s,x,y) for a generator s and two given elements x and y in the group; x should be entered in response to "first", y in response to "second". The generator should be entered as 'l' or 'r' (depending on whether left or right action is desired), followed by one of the current generator symbols. The result is undefined unless x < y, ys > y and xs < x. The result is looked up in the table if available, computed otherwise. The computation of k-l polynomials is avoided as much as possible. positivity_final/messages/uneq/lrcells.help0000600000175000017500000000037307743521425022737 0ustar duclouxducloux00000000000000 The command "lrcells" prints out the left cells in the group, for the current choice of parameters. The cells are sorted in ShortLex order (for the current ordering of the generators), and printed in the ShortLex order of their smallest element. positivity_final/messages/uneq/lcorder.help0000600000175000017500000000121710000214731022702 0ustar duclouxducloux00000000000000 The command "lcorder" prints out the ordering of the left cells for the current group, for the current choice of parameters. This is by definition the ordered set associated to the oriented graph which defines the left preorder relation, where we have an arrow x->y if there exists an s in S such that the coefficient of c_y in the product c_s.c_x is non-zero. The output file contains a printout of the (dual) Hasse diagram of the "abstract" poset, in the numbering of the vertices obtained by ordering the cells in the shortLex order of their shortLex-smallest elements, for the shortLex order corresponding to the current ordering of the vertices. positivity_final/messages/uneq/lrcorder.mess0000600000175000017500000000011010000214763023077 0ustar duclouxducloux00000000000000 sorry, command "lcorder" is currently defined only for finite groups. positivity_final/messages/uneq/lrcorder.help0000600000175000017500000000126710000215005023064 0ustar duclouxducloux00000000000000 The command "lrcorder" prints out the ordering of the two-sided cells for the current group, for the current choice of parameters. This is by definition the ordered set associated to the oriented graph which defines the two-sided preorder relation, where we have an arrow x->y if there exists an s in S such that the coefficient of c_y in the product c_s.c_x or in the product c_x.c_s is non-zero. The output file contains a printout of the (dual) Hasse diagram of the "abstract" poset, in the numbering of the vertices obtained by ordering the cells in the shortLex order of their shortLex-smallest elements, for the shortLex order corresponding to the current ordering of the vertices. positivity_final/messages/uneq/rcorder.help0000600000175000017500000000122110000215073022703 0ustar duclouxducloux00000000000000 The command "rcorder" prints out the ordering of the right cells for the current group, for the current choice of parameters. This is by definition the ordered set associated to the oriented graph which defines the right preorder relation, where we have an arrow x->y if there exists an s in S such that the coefficient of c_y in the product c_x.c_s is non-zero. The output file contains a printout of the (dual) Hasse diagram of the "abstract" poset, in the numbering of the vertices obtained by ordering the cells in the shortLex order of their shortLex-smallest elements, for the shortLex order corresponding to the current ordering of the vertices. positivity_final/messages/uneq/rcells.help0000600000175000017500000000037207743521367022567 0ustar duclouxducloux00000000000000 The command "lcells" prints out the left cells in the group, for the current choice of parameters. The cells are sorted in ShortLex order (for the current ordering of the generators), and printed in the ShortLex order of their smallest element. positivity_final/messages/uneq/rcorder.mess0000600000175000017500000000011010000215033022712 0ustar duclouxducloux00000000000000 sorry, command "rcorder" is currently defined only for finite groups. positivity_final/messages/rcells.mess0000600000175000017500000000010707742540645021631 0ustar duclouxducloux00000000000000 sorry, command "rcells" is currently defined only for finite groups. positivity_final/messages/lcorder.help0000600000175000017500000000124610000212072021730 0ustar duclouxducloux00000000000000 The "lcorder" command prints out the ordering of the left cells for the current group. This is by definition the ordered set associated to the W-graph seen as an oriented graph; recall that if the group is a finite Weyl group, this is also the poset of primitive ideals with trivial central character of the universal enveloping algebra of the corresponding semisimple Lie algebra. The output file contains a printout of the (dual) Hasse diagram of the "abstract" poset, in the numbering of the vertices obtained by ordering the cells in the shortLex order of their shortLex-smallest elements, for the shortLex order corresponding to the current ordering of the vertices. positivity_final/messages/rcells.help0000600000175000017500000000124707742542161021613 0ustar duclouxducloux00000000000000 The command "rcells" prints out the right cells in the group, together with the corresponding W-graphs. The cells are sorted in ShortLex order (for the current ordering of the generators), and printed in the ShortLex order of their smallest element. In the default output mode, the W-graphs in the following format : for each of the cells, in increasing order, we output one line per vertex of the cell, containing a list of pairs (e;mu), one for each edge originating from that vertex, where e is the extremity of the edge, and mu is the corresponding mu-coefficients. The file-output formats will include comments in their files explaining the output format which is used. positivity_final/messages/sstratification.help0000600000175000017500000000121610001230147023505 0ustar duclouxducloux00000000000000 In geometric language, the "sstratification" command prints out the irreducible components of the strata in the singular locus of the Schubert variety X_y, defined by the values of the Kazhdan-Lusztig polynomial P_{x,y}. In other words, we look at the set of x < y such that P_{x,y} has a given value != 1, and take the maximal elements in these sets. In the cases where there really is a Schubert variety (i.e. for crystallographic Coxeter groups), it is known that P_{x,y} is a coefficient-wise decreasing function of x. Note that the ordering we use (the shortlex ordering on x) is precisely reversed from the one that is used in Goresky's files. positivity_final/messages/rcorder.help0000600000175000017500000000124710000212120021731 0ustar duclouxducloux00000000000000 The command "rcorder" prints out the ordering of the right cells for the current group. This is by definition the ordered set associated to the W-graph seen as an oriented graph; recall that if the group is a finite Weyl group, this is also the poset of primitive ideals with trivial central character of the universal enveloping algebra of the corresponding semisimple Lie algebra. The output file contains a printout of the (dual) Hasse diagram of the "abstract" poset, in the numbering of the vertices obtained by ordering the cells in the shortLex order of their shortLex-smallest elements, for the shortLex order corresponding to the current ordering of the vertices. positivity_final/messages/uneq.help10000600000175000017500000000030107743200071021336 0ustar duclouxducloux00000000000000 You are currently in the uneq mode of the program; this makes available the commands for unequal-parameter kazhdan-lusztig functions. The commands available in this mode are the following : positivity_final/messages/uneq.help20000600000175000017500000000012707743200114021343 0ustar duclouxducloux00000000000000 Type the command name in help mode for more information. Type "q" to exit help mode. positivity_final/messages/invpol.help0000600000175000017500000000022207772731254021634 0ustar duclouxducloux00000000000000 The "invpol" command prints out a single inverse K-L polynomial Q_{x,y}. You should enter x as response to "first", y as response to "second". positivity_final/messages/input.help0000600000175000017500000000462007772463742021476 0ustar duclouxducloux00000000000000 We have attempted to make input of group elements (interactively or from a file) as pleasant as possible. The parsing rules for reading an element are as follows. A valid input string is a sequence of group elements. A group element is (a) a word in the generators (b) a context number (the symbol % followed by an integer smaller than the size of the current enumerated part) (c) (for SmallCoxGroups only) a "dense array" number (the symbol # followed by an integer representing a group element, which would be its context number if the context were constructed from the normal form of the longest element in the standard internal numbring of the generators) (d) an expression of the form (w), where w is a valid input string, possibly followed in each case by a string of "modifiers" acting as unary postfix operators. The modifiers are ! (indicating that we go over to the inverse); ^ followed by an integer, indicating exponentiation; or (for finite groups only) *, indicating that we multiply on the right by the longest element. They are right associative. In each case, integers are optional white space followed by either a sequence of decimal digits, or a sequence of hexadecimal digits preceded by 0x. NOTE : to simplify the parsing a little bit, actually the empty string of group elements (an input string made up entirely of whitespace) is always allowed, even in the presence of prefixes and postfixes (and of course it represents the identity.) The rules for reading CoxWords are again as follows : a Coxword is of the form prefix [generator [separator generator]*] postfix, where prefix, separator, postfix are the current input symbols of that name, and generator is a current input symbol for a generator. Each of prefix, postfix and separator may be empty. If postfix is non-empty, reading continues until the first postfix is reached (and a well-formed word is obtained); otherwise, it continues as long as the group element can be possibly extended. Reading fails if at that point the expression is not a correct group element expression. In interactive input, the user is given a second chance when the input is not a valid input string; the string is parsed as far as it makes sense, and the user is prompted to change the sequel (unfortunately we have not been able to unbuffer keyboard input in order to allow correction of earlier terms.) The ? symbol acts as an escape character to get out of this input loop. positivity_final/messages/uneq.help0000600000175000017500000000023207743200654021267 0ustar duclouxducloux00000000000000 The "uneq" command puts the program in unequal-parameter mode. This replaces the various kazhdan-lusztig commands by their unequal-parameter analogues. positivity_final/messages/betti.help0000600000175000017500000000042010001244374021411 0ustar duclouxducloux00000000000000 The "betti" command prints out the ordinary Betti numbers for the interval [e,y]. Unfortunately the computation of the Betti numbers for an arbitrary interval [x,y] is not implemented --- to do it right would require more time than I can affor to spend on it right now! positivity_final/messages/ihbetti.help0000600000175000017500000000064610001245000021727 0ustar duclouxducloux00000000000000 The "ihbetti" command prints out the coefficients of the polynomial \sum_{x\leq y} P_{x,y}q^{l(y)-l(x)}. These are the betti numbers of the intersection cohomology of the Schubert variety X_y in the case where W is crystallographic. In that case, they are known to satisfy Poincare duality; actually this is conjectured to hold in general, and the program will scream a congratulation if it ever finds a counterexample. positivity_final/messages/rcwgraphs.help0000600000175000017500000000105110000202421022265 0ustar duclouxducloux00000000000000 The "rcwgraphs" command prints out the W-graphs of the right cells in the group. The cells are sorted in ShortLex order (for the current ordering of the generators); this is the order in which they are output by the "rcells" command. In the default output mode, the graphs are numbered by the number of the corresponding cell in the above ordering; they are output in the default format for W-graphs (one line per node, starting wtih the descent set, and followed by the edge-list). See the help message for the "rwgraph" command for more details. positivity_final/messages/lcorder.mess0000600000175000017500000000011010000213304021733 0ustar duclouxducloux00000000000000 sorry, command "lcorder" is currently defined only for finite groups. positivity_final/messages/lrcorder.help0000600000175000017500000000073610000212141022112 0ustar duclouxducloux00000000000000 The command "lrcorder" prints out the ordering of the two-sided cells for the current group. This is by definition the ordered set associated to the W-graph seen as an oriented graph. The output file contains a printout of the (dual) Hasse diagram of the "abstract" poset, in the numbering of the vertices obtained by ordering the cells in the shortLex order of their shortLex-smallest elements, for the shortLex order corresponding to the current ordering of the vertices. positivity_final/messages/rcorder.mess0000600000175000017500000000011010000213752021750 0ustar duclouxducloux00000000000000 sorry, command "rcorder" is currently defined only for finite groups. positivity_final/messages/fullcontext.help0000600000175000017500000000033707771716365022710 0ustar duclouxducloux00000000000000 The "fullcontext" command extends the enumerated part of the group to the full group --- of course, ti is available for finite groups only. It is invoked automatically before commands that compute all cells in the group. positivity_final/messages/inorder.help0000600000175000017500000000123607760127145021770 0ustar duclouxducloux00000000000000 The "inorder" command compares two elements in the group, using only elementary string operations (and hence not consuming any memory). The algorithm is as follows : let s be a generator s.t. hs < h; then if gs < g, g<=h iff gs<=hs; otherwise g<=h iff g<=hs. Of course this is very slow and not suitable for large-scale computations. If the comparison is true, the program will indicate the set of erasure points in h which lead to g. Not that the erasures are made from a reduced expression of g (one such can be gotten with the compute command); also, they could well lead to an expression for h which is different from the one you entered, even if it was reduced. positivity_final/messages/lrcorder.mess0000600000175000017500000000011110000214002022112 0ustar duclouxducloux00000000000000 sorry, command "lrcorder" is currently defined only for finite groups. positivity_final/messages/cprod.help0000644000175000017500000000056110115363563021437 0ustar duclouxducloux00000000000000 Given two elements x and y of the group, the cprod command computes the product c_x.c_y of the two corresponding Kazhdan-Lustig basis elements, in the KL basis, and prints the result on the standard output. NOTE : as the coefficients are always _symmetric_ Laurent polynomials in the indeterminate v, we only output half of them (the terms with nonnegative degree.) positivity_final/messages/cycltable.help0000644000175000017500000000061510246626222022271 0ustar duclouxducloux00000000000000 Given an element y of the group, the cycltable command prints out the table of all the products c_x.c_y of elements of the Kazhdan-Lusztig basis, as x runs through the group. The user can specify an output file; the default is stdout. NOTE : as the coefficients are always _symmetric_ Laurent polynomials in the indeterminate v, we only output half of them (the terms with nonnegative degree.) positivity_final/messages/decrklpol.help0000644000175000017500000000042410115364412022277 0ustar duclouxducloux00000000000000 The decrklpol command checks the property that whenever x <= z <= y in the group, the Kazhdan-Lusztig polynomial P_{z,y} is always <= P_{x,y}, in the sense that P_{x,y}-P_{z,y} has nonnegative coefficients. This is known in general for finite Weyl groups by work of Irving. positivity_final/messages/klplist.help0000644000175000017500000000040010115364567022007 0ustar duclouxducloux00000000000000 The klplist command outputs the list of all distinct Kazhdan-Lusztig polynomials which occur in the group. For example, for F4 there should be 313. In particular, it is then a trivial matter to check properties such as nonnegativity of the coefficients. positivity_final/messages/positivity.help0000644000175000017500000000153510246623250022552 0ustar duclouxducloux00000000000000 The "positivity" command checks the non-negativity of the structure constants for the Hecke algebra in the Kazhdan-Lusztig basis. In the process, it checks that the coefficients are in fact unimodal, as explained in the accompanying paper (this translates into the fact that for the half of the Laurent polynomial that is actually printed, the coefficients of the appropriate parity form an increasing sequence when counted from the top.) For the group H4, which is the main case of interest, you should expect a running time of several days, and you should have a sizeable amount of memory available (at least 2 Gb for a 32-bit machine, and at least 3 for a 64-bit machine.) The program outputs a log of its process (one line per group element processed) in the file positivity_log, and records any errors (there shouldn't be any!) in the file error_log. positivity_final/bits.h0000600000175000017500000003661010011171251016737 0ustar duclouxducloux00000000000000/* This is bits.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef BITS_H /* guarantee single inclusion */ #define BITS_H #include "globals.h" #include #include #include "list.h" namespace bits { using namespace globals; using namespace list; }; /******** type declarations *************************************************/ namespace bits { class BitMap; class Partition; class PartitionIterator; class Permutation; class SubSet; typedef unsigned char Flags; typedef Ulong LFlags; typedef Ulong SetElt; typedef List Set; }; /******** function declarations *********************************************/ #include "io.h" namespace bits { using namespace io; }; namespace bits { String& append(String& l, const BitMap& map); unsigned bitCount(const LFlags& f); bool isRefinement(const Partition& pi1, const Partition& pi2); void memSet(void *dest, void *source, Ulong size, Ulong count); void print(FILE* file, const BitMap& map); template void rightRangePermute(List& r, const Permutation& a); template void sortI(const List& r, Permutation& a); template void sortI(const List& r, C& inOrder, Permutation& a); template void sortI_f(const List& r, F& f, Permutation& a); }; /******** type definitions **************************************************/ #include "constants.h" namespace bits { using namespace constants; }; class bits::Permutation:public Set { public: /* constructors and destructors */ Permutation(); Permutation(const Ulong& n); ~Permutation(); /* manipulators */ Permutation& identity(const Ulong& n); Permutation& inverse(); Permutation& compose(const Permutation& a); Permutation& rightCompose(const Permutation& a); }; class bits::BitMap { private: List d_map; Ulong d_size; public: /* constructors and destructors */ BitMap() {}; BitMap(const Ulong& n); BitMap(const BitMap& map): d_map(map.d_map), d_size(map.d_size) {}; ~BitMap(); /* standard destructor */ /* modifiers */ BitMap& operator=(const BitMap& map); /* inlined */ BitMap& assign(const BitMap& map); void clearBit(const Ulong& n); /* inlined */ void permute(Permutation& q); void reset(); /* inlined */ void setBit(const Ulong& n); /* inlined */ void setBit(const Ulong& n, const bool& t); /* inlined */ void setSize(const Ulong& n); /* operations */ void operator~ (); void operator&= (const BitMap& map); void operator|= (const BitMap& map); void andnot(const BitMap& map); /* accessors */ Ulong bitCount() const; LFlags chunk(const Ulong& m) const; /* inlined */ Ulong firstBit() const; bool isEmpty(const Ulong& m) const; Ulong lastBit() const; LFlags lastchunk() const; /* inlined */ bool getBit(const Ulong& n) const; /* inlined */ Ulong size() const; /* inlined */ /* iterator */ class Iterator; class ReverseIterator; friend class Iterator; Iterator begin() const; Iterator end() const; ReverseIterator rbegin() const; /* inlined */ ReverseIterator rend() const; /* inlined */ }; class bits::BitMap::Iterator { /* is really a constant iterator */ private: static const LFlags posBits = BITS(LFlags) - 1; /* BITS(LFlags should be a power of two) */ static const LFlags baseBits = ~posBits; const BitMap* d_b; LFlags* d_chunk; Ulong d_bitAddress; public: Iterator(); Iterator(const BitMap& b); ~Iterator(); Ulong bitPos() const; /* inlined */ Ulong operator* () const; /* inlined */ Iterator& operator++ (); Iterator& operator-- (); bool operator== (const Iterator& i) const; /* inlined */ bool operator!= (const Iterator& i) const; /* inlined */ /* friend declaration */ friend Iterator BitMap::end() const; }; class bits::BitMap::ReverseIterator { private: Iterator d_i; public: ReverseIterator() {}; explicit ReverseIterator(const Iterator& i):d_i(i) {}; ~ReverseIterator() {}; Ulong operator* () const; /* inlined */ ReverseIterator& operator++ (); /* inlined */ ReverseIterator& operator-- (); /* inlined */ bool operator== (const ReverseIterator& i) const; /* inlined */ bool operator!= (const ReverseIterator& i) const; /* inlined */ }; class bits::Partition { private: List d_list; Ulong d_classCount; public: /* class definitions */ typedef Ulong valueType; /* constructors and destructors */ Partition(); Partition(const Ulong &n); Partition(const Partition& a, const BitMap& b); template Partition(const List& r, F& f); template Partition(const I& first, const I& last, F& f); ~Partition(); /* accessors */ const Ulong& operator() (const Ulong& j) const; /* inlined */ Ulong classCount() const; /* inlined */ Ulong size() const; /* inlined */ void sort(Permutation& a) const; void sortI(Permutation& a) const; void writeClass(BitMap& b, const Ulong& n) const; /* modifiers */ Ulong& operator[] (const Ulong& j); /* inlined */ void normalize(); void normalize(Permutation& a); void permute(const Permutation& a); void permuteRange(const Permutation& a); void setClassCount(); void setClassCount(const Ulong& count); /* inlined */ void setSize(const Ulong &n); /* inlined */ /* input/output */ void printClassSizes(FILE* file) const; }; class bits::PartitionIterator { const Partition& d_pi; Permutation d_a; Set d_class; Ulong d_base; bool d_valid; public: /* constructors and destructors */ PartitionIterator(const Partition& pi); ~PartitionIterator(); /* iterator operations */ operator bool() const; /* inlined */ void operator++(); const Set& operator()() const; /* inlined */ }; class bits::SubSet { private: BitMap d_bitmap; List d_list; public: /* constructors and destructors */ SubSet() {}; SubSet(const Ulong& n):d_bitmap(n), d_list(0) {}; SubSet(const SubSet& q):d_bitmap(q.d_bitmap), d_list(q.d_list) {}; ~SubSet(); /* standard destructor */ /* accessors */ const Ulong& operator[] (const Ulong& j) const; /* inlined */ const BitMap& bitMap() const; /* inlined */ Ulong find(const SetElt& x) const; /* inlined */ bool isMember(const Ulong& n) const; /* inlined */ Ulong size() const; /* inlined */ /* modifiers */ Ulong& operator[] (const Ulong& j); /* inlined */ void add(const Ulong& n); SubSet& assign(const SubSet& q); /* inlined */ BitMap& bitMap(); /* inlined */ void readBitMap(); void reset(); void setBitMapSize(const Ulong& n); /* inlined */ void setListSize(const Ulong& n); /* inlined */ void sortList(); /* inlined */ }; /**** Inline implementations **********************************************/ namespace bits { inline BitMap& BitMap::operator= (const BitMap& map) {return assign(map);} inline void BitMap::clearBit(const Ulong& n) {d_map[n/BITS(LFlags)] &= ~(lmask[n%BITS(LFlags)]);} inline LFlags BitMap::chunk(const Ulong& m) const {return d_map[m];} inline bool BitMap::getBit(const Ulong& n) const {return d_map[n/BITS(LFlags)] & lmask[n%BITS(LFlags)];} inline LFlags BitMap::lastchunk() const {return leqmask[(size()-1)%BITS(LFlags)];} inline void BitMap::reset() {d_map.setZero();} inline void BitMap::setBit(const Ulong& n) {d_map[n/BITS(LFlags)] |= lmask[n%BITS(LFlags)];} inline void BitMap::setBit(const Ulong& n, const bool& t) {if (t) setBit(n); else clearBit(n);} inline Ulong BitMap::size() const {return d_size;} inline BitMap::ReverseIterator BitMap::rbegin() const {return ReverseIterator(end());} inline BitMap::ReverseIterator BitMap::rend() const {return ReverseIterator(begin());} inline Ulong BitMap::Iterator::bitPos() const {return d_bitAddress&posBits;} inline Ulong BitMap::Iterator::operator* () const {return d_bitAddress;} inline bool BitMap::Iterator::operator== (const BitMap::Iterator& i) const {return d_bitAddress == i.d_bitAddress;} inline bool BitMap::Iterator::operator!= (const BitMap::Iterator& i) const {return d_bitAddress != i.d_bitAddress;} inline Ulong BitMap::ReverseIterator::operator* () const {Iterator tmp(d_i); --tmp; return *tmp;} inline BitMap::ReverseIterator& BitMap::ReverseIterator::operator++ () {--d_i; return *this;} inline BitMap::ReverseIterator& BitMap::ReverseIterator::operator-- () {++d_i; return *this;} inline bool BitMap::ReverseIterator::operator== (const ReverseIterator& i) const {return d_i == i.d_i;} inline bool BitMap::ReverseIterator::operator!= (const ReverseIterator& i) const {return d_i != i.d_i;} inline const Ulong& Partition::operator() (const Ulong &j) const {return d_list[j];} inline Ulong& Partition::operator[] (const Ulong &j) {return d_list[j];} inline Ulong Partition::classCount() const {return d_classCount;} inline void Partition::setClassCount(const Ulong& count) {d_classCount = count;} inline void Partition::setSize(const Ulong& n) {d_list.setSize(n);} inline Ulong Partition::size() const {return d_list.size();} inline PartitionIterator::operator bool() const {return d_valid;} inline const Set& PartitionIterator::operator()() const {return d_class;} inline Ulong& SubSet::operator[] (const Ulong& j) {return d_list[j];} inline const Ulong& SubSet::operator[] (const Ulong& j) const {return d_list[j];} inline SubSet& SubSet::assign(const SubSet& q) {new(this) SubSet(q); return *this;} inline const BitMap& SubSet::bitMap() const {return d_bitmap;} inline BitMap& SubSet::bitMap() {return d_bitmap;} inline Ulong SubSet::find(const SetElt& x) const {return list::find(d_list,x);} inline bool SubSet::isMember(const Ulong& n) const {return d_bitmap.getBit(n);} inline void SubSet::setBitMapSize(const Ulong& n) {d_bitmap.setSize(n);} inline void SubSet::setListSize(const Ulong& n) {d_list.setSize(n);} inline Ulong SubSet::size() const {return d_list.size();} inline void SubSet::sortList() {return d_list.sort();} }; /******** template definitions ***********************************************/ namespace bits { template Partition::Partition(const List& r, F& f) :d_list(0) /* This constructor defines the partition of [0,r.size()[ defined by f; f is supposed to be a function taking arguments of type T. It is also assumed that operator<= is defined for the value type of f (so that the function insert may be applied.) */ { List c(0); for (Ulong j = 0; j < r.size(); ++j) { insert(c,f(r[j])); } d_list.setSize(r.size()); d_classCount = c.size(); for (Ulong j = 0; j < r.size(); ++j) { d_list[j] = find(c,f(r[j])); } } template Partition::Partition(const I& first, const I& last, F& f):d_list(0) /* A rather general partition constructor. It is assumed that I is an Input Iterator (in an informal sense). It is assumed that f is a functor taking one argument of type the value type of I, and that operator<= is defined for the value type of f. A partition is constructed on the range [0,N[, where N is the number of iterations from first to last; the class numbers are attributed in the order of the values of f on the range. */ { List c(0); Ulong count = 0; for (I i = first; i != last; ++i) { insert(c,f(*i)); count++; } d_list.setSize(count); d_classCount = c.size(); count = 0; for (I i = first; i != last; ++i) { d_list[count] = find(c,f(*i)); count++; } } template void rightRangePermute(List& r, const Permutation& a) /* Applies the permutation a to the range of the list, on the right (this amounts to applying the inverse permutation in the usual sense). In other words, we have new[j] = old[a[j]]. We cannot write this directly however, or we would overwrite. So we do something similar as with ordinary range permutations. */ { BitMap b(r.size()); for (Ulong j = 0; j < a.size(); ++j) { if (b.getBit(j)) continue; if (a[j] == j) { b.setBit(j); continue; } Ulong k = j; b.setBit(j); for (Ulong i = a[j]; i != j; i = a[i]) { T buf = r[k]; r[k] = r[i]; r[i] = buf; k = i; b.setBit(i); } } return; } template void sortI(const List& r, Permutation& a) /* General sort function for lists. It is assumed that operator <= is defined for T; we will use operator> instead of !operator<=. Doesn't actually modify r; it only writes down in a the permutation s.t. new[j] = old[a[j]]. */ { a.identity(r.size()); /* set the starting value of h */ Ulong h = 1; for (; h < r.size()/3; h = 3*h+1) ; /* do the sort */ for (; h > 0; h /= 3) { for (Ulong j = h; j < r.size(); ++j) { Ulong buf = a[j]; Ulong i = j; for (; (i >= h) && (r[a[i-h]] > r[buf]); i -= h) a[i] = a[i-h]; a[i] = buf; } } return; } template void sortI(const List& r, C& inOrder, Permutation& a) /* General sort function taking a comparison functor as a parameter. It is assumed that inOrder takes two arguments of type T, and returns a boolean value, so that the corresponding relation is a total preorder relation. Doesn't actually modify r; it only writes down in a the permutation s.t. new[j] = old[a[j]]. */ { a.identity(r.size()); /* set the starting value of h */ Ulong h = 1; for (; h < r.size()/3; h = 3*h+1) ; /* do the sort */ for (; h > 0; h /= 3) { for (Ulong j = h; j < r.size(); ++j) { Ulong buf = a[j]; Ulong i = j; for (; (i >= h) && !inOrder(r[a[i-h]],r[buf]); i -= h) a[i] = a[i-h]; a[i] = buf; } } return; } template void sortI_f(const List& r, F& f, Permutation& a) /* General sort function where the comparison is made using a functor f. It is assumed that operator> is defined for the valuetype of f. Doesn't actually modify r; it only writes down in a the permutation s.t. new[j] = old[a[j]]. */ { a.identity(r.size()); /* set the starting value of h */ Ulong h = 1; for (; h < r.size()/3; h = 3*h+1) ; /* do the sort */ for (; h > 0; h /= 3) { for (Ulong j = h; j < r.size(); ++j) { Ulong buf = a[j]; Ulong i = j; for (; (i >= h) && (f(r[a[i-h]]) > f(r[buf])); i -= h) a[i] = a[i-h]; a[i] = buf; } } return; } }; #endif positivity_final/cells.cpp0000600000175000017500000007437010011171251017440 0ustar duclouxducloux00000000000000/* This is cells.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "cells.h" #include "stack.h" namespace cells { using namespace klsupport; using namespace stack; }; /**************************************************************************** This module contains code for the computation of Kazhdan-Lustig cells for the group (say in the finite case; in the infinite case the best we can hope for is to get pieces of cells.) The main tool for this seems to be the systematic use of *-operations; this is particularly effective in the simply laced cases, but very useful also in the other ones. These operations are recalled and implemented in the Schubert module. Let us recall the results that we use here, all contained in the original Inventiones paper of Kazhdan and Lusztig. Each left cell is stable under left *-operations (insofar as they are defined); in other terms for each x such that *x (w.r.t. some simple edge {s,t}) is defined, *x is left- equivalent to x. So left cells are unions of left star-orbits (in type A, it is even so that the left cells are the left star-orbits.) Furthermore, the domain of every right star-operation is a union of right equi-descent classes, and therefore a union of left cells; and the operation takes left cells to left cells isomorphically as W-graphs. In particular also, each two-sided cell is a union of two-sided star orbits. So our first goal should be to try to get at the functions defining the partitions in left, right and two-sided cells, computing as few mu-coefficients as possible; then we will want to determine the full W-graph structure on the cells, classify them up to isomorphism, and have functions such as "get the (left, right, 2-sided) cell of an element." More sophisticated data for cells (distinguished involutions, a-functions ...) will have to wait a little bit more. ****************************************************************************/ namespace { using namespace cells; typedef List CoxList; }; /**************************************************************************** Chapter I -- Partitions This section contains functions that define partitions of (subsets of) the context, useful for cell-computations. The following functions are defined : - lCells(pi,p), rCells(pi,kl), lrCells(pi,kl) : partition of the context into left (right, two-sided) kazhdan-lusztig cells; - lDescentPartition(pi,p), rDescentPartititon(pi,p) : partition of p according to left (right) descent sets; - lStringEquiv(pi,p), rStringEquiv(pi,p) : partition of p according to weak Bruhat equivalences; - lGeneralizedTau(pi,p), rGeneralizedTau(pi,p) : left (right) descent partition, stabilized under star operations; ****************************************************************************/ namespace cells { void lCells(Partition& pi, kl::KLContext& kl) /* This function puts in pi the partition of p into left cells --- in the case of an incomplete context, they will be the cells defined by the links in the graph. The idea will be to minimize k-l computations. We proceed as follows. First, we determine the generalized-tau partition of the context. Then, we look at the star-orbits among the tau-classes, and decompose one representative of each into cells; we propagate the cells using star-operations. */ { static SubSet q(0); static SubSet a(0); static WGraph X(0); static Partition qcells(0); static List cell_count(0); static List qcell_count(0); static OrientedGraph P(0); static Fifo orbit; const SchubertContext& p = kl.schubert(); q.setBitMapSize(p.size()); a.setBitMapSize(p.size()); a.reset(); cell_count.setSize(0); rGeneralizedTau(pi,p); for (CoxNbr x = 0; x < p.size(); ++x) { /* a holds the elements already processed */ if (a.isMember(x)) continue; /* put the next generalized-tau class in q */ q.reset(); pi.writeClass(q.bitMap(),pi(x)); q.readBitMap(); /* put cell-partition of q in qcells */ X.reset(); lWGraph(X,q,kl); X.graph().cells(qcells,&P); /* the fifo-list orbit is used to traverse the *-orbit of the first element of the current generalized-tau class */ orbit.push(a.size()); qcell_count.setSize(0); /* get class counts and mark off cells in q */ for (PartitionIterator i(qcells); i; ++i) { const Set& c = i(); qcell_count.append(c.size()); cell_count.append(c.size()); for (Ulong j = 0; j < c.size(); ++j) a.add(q[c[j]]); } /* propagate cells with star-operations; the idea is that star operations act on the level of generalized-tau classes, so each element in a given generalized-tau class accepts the same language. */ while (orbit.size()) { Ulong c = orbit.pop(); CoxNbr z = a[c]; for (StarOp j = 0; j < p.nStarOps(); ++j) { CoxNbr zj = p.star(z,j); if (zj == undef_coxnbr) continue; if (a.isMember(zj)) continue; /* mark off orbit */ orbit.push(a.size()); for (Ulong i = 0; i < q.size(); ++i) { CoxNbr y = a[c+i]; CoxNbr yj = p.star(y,j); a.add(yj); } for (Ulong i = 0; i < qcell_count.size(); ++i) { cell_count.append(qcell_count[i]); } } } } /* write down the partition */ Ulong c = 0; for (Ulong j = 0; j < cell_count.size(); ++j) { for (Ulong i = 0; i < cell_count[j]; ++i) { pi[a[c+i]] = j; } c += cell_count[j]; } pi.setClassCount(cell_count.size()); return; } void rCells(Partition& pi, kl::KLContext& kl) /* Same as lCells, but does the partition into right cells. */ { static SubSet q(0); static SubSet a(0); static WGraph X(0); static Partition qcells(0); static List cell_count(0); static List qcell_count(0); static OrientedGraph P(0); static Fifo orbit; static Permutation v(0); const SchubertContext& p = kl.schubert(); q.setBitMapSize(p.size()); a.setBitMapSize(p.size()); a.reset(); cell_count.setSize(0); lGeneralizedTau(pi,p); for (CoxNbr x = 0; x < p.size(); ++x) { if (a.isMember(x)) continue; /* get the next generalized-tau class */ q.reset(); pi.writeClass(q.bitMap(),pi(x)); q.readBitMap(); /* find cells in class */ X.reset(); rWGraph(X,q,kl); X.graph().cells(qcells,&P); /* the fifo-list orbit is used to traverse the *-orbit of the first element of the current generalized-tau class */ orbit.push(a.size()); qcell_count.setSize(0); /* get class counts and mark off cells in q */ for (PartitionIterator i(qcells); i; ++i) { const Set& c = i(); qcell_count.append(c.size()); cell_count.append(c.size()); for (Ulong j = 0; j < c.size(); ++j) a.add(q[c[j]]); } /* propagate cells with star-operations */ while (orbit.size()) { Ulong c = orbit.pop(); CoxNbr z = a[c]; for (StarOp j = p.nStarOps(); j < 2*p.nStarOps(); ++j) { CoxNbr zj = p.star(z,j); if (zj == undef_coxnbr) continue; if (a.isMember(zj)) continue; /* mark off orbit */ orbit.push(a.size()); for (Ulong i = 0; i < q.size(); ++i) { CoxNbr y = a[c+i]; CoxNbr yj = p.star(y,j); a.add(yj); } for (Ulong i = 0; i < qcell_count.size(); ++i) { cell_count.append(qcell_count[i]); } } } } /* write down the partition */ Ulong c = 0; for (Ulong j = 0; j < cell_count.size(); ++j) { for (Ulong i = 0; i < cell_count[j]; ++i) { pi[a[c+i]] = j; } c += cell_count[j]; } pi.setClassCount(cell_count.size()); return; } void lrCells(Partition& pi, kl::KLContext& kl) /* This function computes the two-sided cells in the context. There are certainly better ways to do this, but I'm afraid I don't know enough to do it other than by filling in all the mu's ... */ { kl.fillMu(); WGraph X(0); lrWGraph(X,kl); X.graph().cells(pi); return; } void lDescentPartition(Partition& pi, const SchubertContext& p) /* This function writes in pi the partition of p according to the left descent sets. */ { static List d(0); /* holds the appearing descent sets */ pi.setSize(p.size()); d.setSize(0); for (CoxNbr x = 0; x < p.size(); ++x) insert(d,p.ldescent(x)); for (CoxNbr x = 0; x < p.size(); ++x) pi[x] = find(d,p.ldescent(x)); pi.setClassCount(d.size()); return; } void lStringEquiv(Partition& pi, const SchubertContext& p) /* This function writes in pi the partition of p according to the (left) weak Bruhat links which are equivalences for the W-graph. In other words, x is equivalent to sx if sx > x and the left descent set of x is not contained in the left descent set of sx; this means that there is a t, not commuting with s, in the left descent set of x s.t. x and sx are in the same left chain for {s,t}. */ { static BitMap b(0); static Fifo orbit; b.setSize(p.size()); b.reset(); pi.setSize(p.size()); Ulong count = 0; for (CoxNbr x = 0; x < p.size(); ++x) { if (b.getBit(x)) continue; b.setBit(x); pi[x] = count; orbit.push(x); while (orbit.size()) { CoxNbr z = orbit.pop(); for (Generator s = 0; s < p.rank(); ++s) { CoxNbr sz = p.lshift(z,s); if (b.getBit(sz)) continue; LFlags fz = p.ldescent(z); LFlags fsz = p.ldescent(sz); LFlags f = fz & fsz; if ((f == fz) || (f == fsz)) /* inclusion */ continue; b.setBit(sz); pi[sz] = count; orbit.push(sz); } } count++; } pi.setClassCount(count); return; } void lStringEquiv(Partition& pi, const SubSet& q, const SchubertContext& p) /* Does the partition of the subset q into left string classes. It is assumed that q is stable under the equivalence relation. */ { static BitMap b(0); static Fifo orbit; b.setSize(p.size()); b.reset(); pi.setSize(q.size()); Ulong count = 0; for (Ulong j = 0; j < q.size(); ++j) { const CoxNbr x = q[j]; if (b.getBit(x)) continue; b.setBit(x); pi[j] = count; orbit.push(x); while (orbit.size()) { CoxNbr z = orbit.pop(); for (Generator s = 0; s < p.rank(); ++s) { CoxNbr sz = p.lshift(z,s); if (b.getBit(sz)) continue; LFlags fz = p.ldescent(z); LFlags fsz = p.ldescent(sz); LFlags f = fz & fsz; if ((f == fz) || (f == fsz)) /* inclusion */ continue; if (!q.isMember(sz)) { // q is not stable! this shouldn't happen ERRNO = ERROR_WARNING; return; } b.setBit(sz); orbit.push(sz); } } count++; } pi.setClassCount(count); return; } void rDescentPartition(Partition& pi, const SchubertContext& p) /* This function writes in pi the partition of p according to the right descent sets. */ { static List d(0); /* holds the appearing descent sets */ pi.setSize(p.size()); d.setSize(0); for (CoxNbr x = 0; x < p.size(); ++x) insert(d,p.rdescent(x)); for (CoxNbr x = 0; x < p.size(); ++x) pi[x] = find(d,p.rdescent(x)); pi.setClassCount(d.size()); return; } void rStringEquiv(Partition& pi, const SchubertContext& p) /* Same as lStringEquiv, but on the other side. */ { static BitMap b(0); static Fifo orbit; b.setSize(p.size()); b.reset(); pi.setSize(p.size()); Ulong count = 0; for (CoxNbr x = 0; x < p.size(); ++x) { if (b.getBit(x)) continue; b.setBit(x); pi[x] = count; orbit.push(x); while (orbit.size()) { CoxNbr z = orbit.pop(); for (Generator s = 0; s < p.rank(); ++s) { CoxNbr zs = p.rshift(z,s); if (b.getBit(zs)) continue; LFlags fz = p.rdescent(z); LFlags fzs = p.rdescent(zs); LFlags f = fz & fzs; if ((f == fz) || (f == fzs)) /* inclusion */ continue; b.setBit(zs); pi[zs] = count; orbit.push(zs); } } count++; } pi.setClassCount(count); return; } void rStringEquiv(Partition& pi, const SubSet& q, const SchubertContext& p) /* Same as lStringEquiv, but on the other side. */ { static BitMap b(0); static Fifo orbit; b.setSize(p.size()); b.reset(); pi.setSize(q.size()); Ulong count = 0; for (Ulong j = 0; j < q.size(); ++j) { const CoxNbr x = q[j]; if (b.getBit(x)) continue; b.setBit(x); pi[j] = count; orbit.push(x); while (orbit.size()) { CoxNbr z = orbit.pop(); for (Generator s = 0; s < p.rank(); ++s) { CoxNbr zs = p.rshift(z,s); if (b.getBit(zs)) continue; LFlags fz = p.rdescent(z); LFlags fzs = p.rdescent(zs); LFlags f = fz & fzs; if ((f == fz) || (f == fzs)) /* inclusion */ continue; if (!q.isMember(zs)) { // q is not stable! this shouldn't happen ERRNO = ERROR_WARNING; return; } b.setBit(zs); orbit.push(zs); } } count++; } pi.setClassCount(count); return; } void lGeneralizedTau(Partition& pi, const SchubertContext& p) /* Like rGeneralizedTau, but on the left. */ { static Permutation v(0); static List b(0); static List cc(0); static List a(0); /* initialize pi with partition into right descent sets */ Ulong prev; lDescentPartition(pi,p); v.setSize(pi.size()); do { prev = pi.classCount(); /* refine */ for (Ulong r = p.nStarOps(); r < 2*p.nStarOps(); ++r) { pi.sortI(v); /* sort partition */ Ulong count = pi.classCount(); cc.setSize(count); cc.setZero(); for (Ulong j = 0; j < pi.size(); ++j) cc[pi[j]]++; Ulong i = 0; for (Ulong c = 0; c < pi.classCount(); ++c) { CoxNbr x = v[i]; /* first element in class */ if (p.star(x,r) == undef_coxnbr) goto next_class; /* find possibilities for v[.]*r */ b.setSize(0); for (Ulong j = 0; j < cc[c]; ++j) { Ulong cr = pi[p.star(v[i+j],r)]; insert(b,cr); } if (b.size() > 1) { /* there is a refinement */ a.setSize(cc[c]); for (Ulong j = 0; j < a.size(); ++j) a[j] = find(b,pi[p.star(v[i+j],r)]); for (Ulong j = 0; j < cc[c]; ++j) { if (a[j] > 0) pi[v[i+j]] = count+a[j]-1; } count += b.size()-1; } next_class: i += cc[c]; continue; } pi.setClassCount(count); } } while (prev < pi.classCount()); return; } void rGeneralizedTau(Partition& pi, const SchubertContext& p) /* This is the most delicate of the partition functions. It is the maximal refinement of the right descent partition under right star operations. In other words, two elements x and y are in the same class for this partition, if for each right star-word a (i.e. a sequence of right star-operations), x*a and y*a have the same right descent set. The algorithm is very much like the minimization algorithm for a finite state automaton. NOTE : this could probably be simplified with a PartitionIterator; be wary though of modifications in pi during the loop. */ { static Permutation v(0); static List b(0); static List cc(0); static List a(0); /* initialize pi with partition into right descent sets */ Ulong prev; rDescentPartition(pi,p); v.setSize(pi.size()); do { prev = pi.classCount(); /* refine */ for (Ulong r = 0; r < p.nStarOps(); ++r) { pi.sortI(v); /* sort partition */ Ulong count = pi.classCount(); cc.setSize(count); cc.setZero(); for (Ulong j = 0; j < pi.size(); ++j) cc[pi[j]]++; Ulong i = 0; for (Ulong c = 0; c < pi.classCount(); ++c) { CoxNbr x = v[i]; /* first element in class */ if (p.star(x,r) == undef_coxnbr) goto next_class; /* find possibilities for v[.]*r */ b.setSize(0); for (Ulong j = 0; j < cc[c]; ++j) { Ulong cr = pi[p.star(v[i+j],r)]; insert(b,cr); } if (b.size() > 1) { /* there is a refinement */ a.setSize(cc[c]); for (Ulong j = 0; j < a.size(); ++j) a[j] = find(b,pi[p.star(v[i+j],r)]); for (Ulong j = 0; j < cc[c]; ++j) { if (a[j] > 0) pi[v[i+j]] = count+a[j]-1; } count += b.size()-1; } next_class: i += cc[c]; continue; } pi.setClassCount(count); } } while (prev < pi.classCount()); return; } }; /***************************************************************************** Chapter II -- W-graph construction This section defines functions for the construction of W-graphs : - lGraph(X,kl) : the graph part only, no descent sets; - lrGraph(X,kl) : the graph part only, no descent sets; - rGraph(X,kl) : the graph part only, no descent sets; - lWGraph(X,kl) : constructs a W-graph directly from the k-l data; - lWGraph(X,q,kl) : the same, restricted to a subset; - rWGraph(X,kl) : constructs a W-graph directly from the k-l data; - rWGraph(X,q,kl) : the same, restricted to a subset; *****************************************************************************/ namespace cells { void lGraph(OrientedGraph& X, kl::KLContext& kl) { const SchubertContext& p = kl.schubert(); X.setSize(kl.size()); X.reset(); for (CoxNbr y = 0; y < kl.size(); ++y) { const kl::MuRow& mu = kl.muList(y); for (Ulong j = 0; j < mu.size(); ++j) { if (mu[j].mu != 0) { CoxNbr x = mu[j].x; if (p.ldescent(x) != p.ldescent(y)) /* make an edge from x to y */ X.edge(x).append(y); } } } for (CoxNbr y = 0; y < kl.size(); ++y) { const CoatomList& c = p.hasse(y); for (Ulong j = 0; j < c.size(); ++j) { if ((p.ldescent(c[j])&p.ldescent(y)) != p.ldescent(c[j])) X.edge(c[j]).append(y); if ((p.ldescent(c[j])&p.ldescent(y)) != p.ldescent(y)) X.edge(y).append(c[j]); } } return; } void lrGraph(OrientedGraph& X, kl::KLContext& kl) { const SchubertContext& p = kl.schubert(); X.setSize(kl.size()); X.reset(); for (CoxNbr y = 0; y < kl.size(); ++y) { const kl::MuRow& mu = kl.muList(y); for (Ulong j = 0; j < mu.size(); ++j) { if (mu[j].mu != 0) { CoxNbr x = mu[j].x; if (p.descent(x) != p.descent(y)) /* make an edge from x to y */ X.edge(x).append(y); } } } for (CoxNbr y = 0; y < kl.size(); ++y) { const CoatomList& c = p.hasse(y); for (Ulong j = 0; j < c.size(); ++j) { if ((p.descent(c[j])&p.descent(y)) != p.descent(c[j])) X.edge(c[j]).append(y); if ((p.descent(c[j])&p.descent(y)) != p.descent(y)) X.edge(y).append(c[j]); } } return; } void rGraph(OrientedGraph& X, kl::KLContext& kl) { const SchubertContext& p = kl.schubert(); X.setSize(kl.size()); X.reset(); for (CoxNbr y = 0; y < kl.size(); ++y) { const kl::MuRow& mu = kl.muList(y); for (Ulong j = 0; j < mu.size(); ++j) { if (mu[j].mu != 0) { CoxNbr x = mu[j].x; if (p.rdescent(x) != p.rdescent(y)) /* make an edge from x to y */ X.edge(x).append(y); } } } for (CoxNbr y = 0; y < kl.size(); ++y) { const CoatomList& c = p.hasse(y); for (Ulong j = 0; j < c.size(); ++j) { if ((p.rdescent(c[j])&p.rdescent(y)) != p.rdescent(c[j])) X.edge(c[j]).append(y); if ((p.rdescent(c[j])&p.rdescent(y)) != p.rdescent(y)) X.edge(y).append(c[j]); } } return; } void lWGraph(WGraph& X, kl::KLContext& kl) /* This function constructs a W-graph directly from the k-l data. In other words, we construct a graph with vertex set the elements of p; for each x < y s.t. mu(x,y) != 0, and L(x) != L(y), we set an edge from x to y if L(y) \subset L(x), from y to x if L(x) \subset L(y); the coefficient of this edge will be mu(x,y) in both cases. Also, to each vertex is associated the descent set L(x). Assumes that the mu-table has been filled. NOTE : this should be changed when there will no longer be a mu-table in the current sense. */ { X.setSize(kl.size()); const SchubertContext& p = kl.schubert(); OrientedGraph& Y = X.graph(); // fill in Y lGraph(Y,kl); // fill in coefficients for (CoxNbr y = 0; y < kl.size(); ++y) { CoeffList& c = X.coeffList(y); const EdgeList& e = X.edge(y); c.setSize(e.size()); Length ly = p.length(y); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr x = e[j]; Length lx = p.length(x); if ((lx < ly) || (lx-ly) == 1) c[j] = 1; else c[j] = kl.mu(y,x); } } // fill in descent sets for (CoxNbr y = 0; y < kl.size(); ++y) X.descent(y) = p.ldescent(y); return; } void lWGraph(WGraph& X, const SubSet& q, kl::KLContext& kl) /* This function constructs the left W-graph for the subset q. It is assumed that q is a union of left cells (typically, q might be a right descent class, or one of the classes provided by GeneralizedTau). The difference with the full lWGraph, is that we do _not_ assume that the mu-coefficients have already been computed; we compute them as needed. It is assumed that q is sorted in increasing order. */ { static List qr(0); X.setSize(q.size()); const SchubertContext& p = kl.schubert(); OrientedGraph& Y = X.graph(); BitMap b(p.size()); Y.reset(); for (Ulong j = 0; j < q.size(); ++j) { CoxNbr y = q[j]; Length ly = p.length(y); // set descent set X.descent(j) = p.ldescent(y); p.extractClosure(b,y); b &= q.bitMap(); qr.setSize(0); // qr holds the relative positions within q of the elements <= y for (Ulong i = 0; i < q.size(); ++i) { if (b.getBit(q[i])) qr.append(i); } for (Ulong i = 0; i < qr.size(); ++i) { CoxNbr x = q[qr[i]]; Length lx = p.length(x); if ((ly-lx)%2 == 0) continue; if ((ly-lx) == 1) { /* found a hasse edge */ if ((p.ldescent(x)&p.ldescent(y)) != p.ldescent(x)) { Y.edge(qr[i]).append(j); X.coeffList(qr[i]).append(1); } if ((p.ldescent(x)&p.ldescent(y)) != p.ldescent(y)) { Y.edge(j).append(qr[i]); X.coeffList(j).append(1); } continue; } KLCoeff mu = kl.mu(x,y); if (mu != 0) { if (p.ldescent(x) != p.ldescent(y)) { Y.edge(qr[i]).append(j); X.coeffList(qr[i]).append(mu); } } } } return; } void lrWGraph(WGraph& X, kl::KLContext& kl) /* Like lWGraph, but for two-sided W-graphs. */ { X.setSize(kl.size()); const SchubertContext& p = kl.schubert(); OrientedGraph& Y = X.graph(); // fill in Y lrGraph(Y,kl); // fill in coefficients for (CoxNbr y = 0; y < kl.size(); ++y) { CoeffList& c = X.coeffList(y); const EdgeList& e = X.edge(y); c.setSize(e.size()); Length ly = p.length(y); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr x = e[j]; Length lx = p.length(x); if ((lx < ly) || (lx-ly) == 1) c[j] = 1; else c[j] = kl.mu(y,x); } } // fill in descent sets for (CoxNbr y = 0; y < kl.size(); ++y) X.descent(y) = p.descent(y); return; } void lrWGraph(WGraph& X, const SubSet& q, kl::KLContext& kl) /* This function constructs the left W-graph for the subset q. It is assumed that q is a union of left cells (typically, q might be a right descent class, or one of the classes provided by GeneralizedTau). The difference with the full lWGraph, is that we do _not_ assume that the mu-coefficients have already been computed; we compute them as needed. It is assumed that q is sorted in increasing order. */ { static List qr(0); X.setSize(q.size()); const SchubertContext& p = kl.schubert(); OrientedGraph& Y = X.graph(); BitMap b(p.size()); Y.reset(); for (Ulong j = 0; j < q.size(); ++j) { CoxNbr y = q[j]; Length ly = p.length(y); // set descent set X.descent(j) = p.descent(y); p.extractClosure(b,y); b &= q.bitMap(); qr.setSize(0); // qr holds the relative positions within q of the elements <= y for (Ulong i = 0; i < q.size(); ++i) { if (b.getBit(q[i])) qr.append(i); } for (Ulong i = 0; i < qr.size(); ++i) { CoxNbr x = q[qr[i]]; Length lx = p.length(x); if ((ly-lx)%2 == 0) continue; if ((ly-lx) == 1) { /* found a hasse edge */ if ((p.descent(x)&p.descent(y)) != p.descent(x)) { Y.edge(qr[i]).append(j); X.coeffList(qr[i]).append(1); } if ((p.descent(x)&p.descent(y)) != p.descent(y)) { Y.edge(j).append(qr[i]); X.coeffList(j).append(1); } continue; } KLCoeff mu = kl.mu(x,y); if (mu != 0) { if (p.descent(x) != p.descent(y)) { Y.edge(qr[i]).append(j); X.coeffList(qr[i]).append(mu); } } } } return; } void rWGraph(WGraph& X, kl::KLContext& kl) /* Like lWGraph, but for right W-graphs. */ { X.setSize(kl.size()); const SchubertContext& p = kl.schubert(); OrientedGraph& Y = X.graph(); // fill in Y rGraph(Y,kl); // fill in coefficients for (CoxNbr y = 0; y < kl.size(); ++y) { CoeffList& c = X.coeffList(y); const EdgeList& e = X.edge(y); c.setSize(e.size()); Length ly = p.length(y); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr x = e[j]; Length lx = p.length(x); if ((lx < ly) || (lx-ly) == 1) c[j] = 1; else c[j] = kl.mu(y,x); } } // fill in descent sets for (CoxNbr y = 0; y < kl.size(); ++y) X.descent(y) = p.rdescent(y); return; } void rWGraph(WGraph& X, const SubSet& q, kl::KLContext& kl) /* Like lWGraph, but for right W-graphs. */ { static List qr(0); X.setSize(q.size()); const SchubertContext& p = kl.schubert(); OrientedGraph& Y = X.graph(); BitMap b(p.size()); Y.reset(); for (Ulong j = 0; j < q.size(); ++j) { CoxNbr y = q[j]; Length ly = p.length(y); X.descent(j) = p.rdescent(y); p.extractClosure(b,y); b &= q.bitMap(); qr.setSize(0); for (Ulong i = 0; i < q.size(); ++i) { if (b.getBit(q[i])) qr.append(i); } for (Ulong i = 0; i < qr.size(); ++i) { CoxNbr x = q[qr[i]]; Length lx = p.length(x); if ((ly-lx)%2 == 0) continue; if ((ly-lx) == 1) { /* found a hasse edge */ if ((p.rdescent(x)&p.rdescent(y)) != p.rdescent(x)) { Y.edge(qr[i]).append(j); X.coeffList(qr[i]).append(1); } if ((p.rdescent(x)&p.rdescent(y)) != p.rdescent(y)) { Y.edge(j).append(qr[i]); X.coeffList(j).append(1); } continue; } KLCoeff mu = kl.mu(x,y); if (mu != 0) { if (p.rdescent(x) != p.rdescent(y)) { Y.edge(qr[i]).append(j); X.coeffList(qr[i]).append(mu); } } } } return; } }; /***************************************************************************** Chapter III -- Graph construction for unequal parameters. In the case of unequal parameters, there is no W-graph associated to the situation. However, there is still an oriented graph, defined exactly as in the case of equal parameters, in terms of the mu-coefficients. Here in fact mu^s_{x,y} is defined only when ys > y, xs < x; hence the condition that R(x) and R(y) are distinct is automatically fulfilled. So the edges from y point to the ws s.t. wy > w, and to the z in muTable(s,y) s.t. mu^s_{z,y} != 0. *****************************************************************************/ namespace cells { void lGraph(OrientedGraph& X, uneqkl::KLContext& kl) /* Puts in X the graph corresponding to the left edges in the context. It assumes that the (right) mu-table has been filled. */ { const SchubertContext& p = kl.schubert(); X.setSize(kl.size()); LFlags S = leqmask[kl.rank()-1]; /* reset X */ for (CoxNbr y = 0; y < X.size(); ++y) { EdgeList& e = X.edge(y); e.setSize(0); } /* fill edgelists */ for (CoxNbr y = 0; y < X.size(); ++y) { CoxNbr yi = kl.inverse(y); for (LFlags f = ~p.rdescent(y) & S; f; f &= (f-1)) { Generator s = firstBit(f); const uneqkl::MuRow& muRow = kl.muList(s,y); for (Ulong j = 0; j < muRow.size(); ++j) { Vertex x = kl.inverse(muRow[j].x); EdgeList& e = X.edge(x); e.append(yi); } Vertex sy = kl.inverse(p.shift(y,s)); EdgeList& e = X.edge(sy); e.append(yi); } } /* sort edgelists */ for (CoxNbr y = 0; y < X.size(); ++y) { EdgeList& e = X.edge(y); e.sort(); } return; } void lrGraph(OrientedGraph& X, uneqkl::KLContext& kl) /* Puts in X the graph corresponding to the edges in the context. It assumes that the mu-table has been filled. We also assume that the context is stable under inverses. */ { const SchubertContext& p = kl.schubert(); X.setSize(kl.size()); LFlags S = leqmask[kl.rank()-1]; /* write down right edges */ rGraph(X,kl); /* add left edges */ for (CoxNbr y = 0; y < X.size(); ++y) { Vertex yi = kl.inverse(y); for (LFlags f = ~p.rdescent(y) & S; f; f &= (f-1)) { Generator s = firstBit(f); const uneqkl::MuRow& muRow = kl.muList(s,y); for (Ulong j = 0; j < muRow.size(); ++j) { Vertex x = kl.inverse(muRow[j].x); EdgeList& e = X.edge(x); insert(e,yi); } Vertex sy = kl.inverse(p.shift(y,s)); EdgeList& e = X.edge(sy); insert(e,yi); } } return; } void rGraph(OrientedGraph& X, uneqkl::KLContext& kl) /* Puts in X the graph corresponding to the edges in the context. It assumes that the mu-table has been filled. */ { const SchubertContext& p = kl.schubert(); X.setSize(kl.size()); LFlags S = leqmask[kl.rank()-1]; /* reset X */ for (CoxNbr y = 0; y < X.size(); ++y) { EdgeList& e = X.edge(y); e.setSize(0); } /* make edges */ for (CoxNbr y = 0; y < X.size(); ++y) { for (LFlags f = ~p.rdescent(y) & S; f; f &= (f-1)) { Generator s = firstBit(f); const uneqkl::MuRow& muRow = kl.muList(s,y); for (Ulong j = 0; j < muRow.size(); ++j) { EdgeList& e = X.edge(muRow[j].x); e.append(y); } CoxNbr ys = p.shift(y,s); EdgeList& e = X.edge(ys); e.append(y); } } /* sort lists */ for (CoxNbr y = 0; y < X.size(); ++y) { EdgeList& e = X.edge(y); e.sort(); } return; } }; /***************************************************************************** Chapter IV -- Utilities This section defines some utility functions : - checkClasses(pi,p) : checks the classes of a refined partition; *****************************************************************************/ namespace cells { CoxNbr checkClasses (const Partition& pi, const SchubertContext& p) /* This function checks if the classes of a refined partition are stable under weak equivalence, as they should. */ { static Permutation v(0); static Partition pi_q(0); static SubSet q(0); q.setBitMapSize(p.size()); v.setSize(pi.size()); pi.sortI(v); Ulong i = 0; for (Ulong j = 0; j < pi.classCount(); ++j) { q.reset(); for (; pi(v[i]) == j; ++i) { q.add(v[i]); } lStringEquiv(pi_q,q,p); if (ERRNO) { printf("error in class #%lu\n",j); return q[0]; } } return 0; } }; positivity_final/cells.h0000600000175000017500000000415610011171251017100 0ustar duclouxducloux00000000000000/* This is cells.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef CELLS_H /* guard against multiple inclusions */ #define CELLS_H #include "globals.h" namespace cells { using namespace globals; }; #include "bits.h" #include "kl.h" #include "uneqkl.h" #include "wgraph.h" namespace cells { using namespace bits; using namespace wgraph; }; /******** function declarations **********************************************/ namespace cells { CoxNbr checkClasses(const Partition& pi, const SchubertContext& p); void lCells(Partition& pi, kl::KLContext& kl); void rCells(Partition& pi, kl::KLContext& kl); void lrCells(Partition& pi, kl::KLContext& kl); void lDescentPartition(Partition& pi, const SchubertContext& p); void rDescentPartition(Partition& pi, const SchubertContext& p); void lStringEquiv(Partition& pi, const SchubertContext& p); void lStringEquiv(Partition& pi, const SubSet& q, const SchubertContext& p); void rStringEquiv(Partition& pi, const SchubertContext& p); void rStringEquiv(Partition& pi, const SubSet& q, const SchubertContext& p); void lrStringEquiv(Partition& pi, const SchubertContext& p); void lrStringEquiv(Partition& pi, const SubSet& q, const SchubertContext& p); void lGeneralizedTau(Partition& pi, const SchubertContext& p); void rGeneralizedTau(Partition& pi, const SchubertContext& p); void lGraph(OrientedGraph& X, kl::KLContext& kl); void lrGraph(OrientedGraph& X, kl::KLContext& kl); void rGraph(OrientedGraph& X, kl::KLContext& kl); void lGraph(OrientedGraph& X, uneqkl::KLContext& kl); void lrGraph(OrientedGraph& X, uneqkl::KLContext& kl); void rGraph(OrientedGraph& X, uneqkl::KLContext& kl); void lWGraph(WGraph& X, kl::KLContext& kl); void lWGraph(WGraph& X, const SubSet& q, kl::KLContext& kl); void rWGraph(WGraph& X, kl::KLContext& kl); void rWGraph(WGraph& X, const SubSet& q, kl::KLContext& kl); void lrWGraph(WGraph& X, kl::KLContext& kl); void lrWGraph(WGraph& X, const SubSet& q, kl::KLContext& kl); void printCellPartition(FILE* file, const kl::KLContext& kl); }; #endif positivity_final/commands.cpp0000600000175000017500000023704210022412367020144 0ustar duclouxducloux00000000000000/* This is commands.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "commands.h" #include "directories.h" #include "error.h" #include "fcoxgroup.h" #include "help.h" #include "interactive.h" #include "special.h" #include "typeA.h" namespace commands { using namespace directories; using namespace error; using namespace fcoxgroup; using namespace help; using namespace interactive; }; namespace { using namespace commands; using namespace stack; bool wgraph_warning = true; /* used in the definition of command trees */ struct Empty_tag {}; struct Interface_tag {}; struct Main_tag {}; struct Uneq_tag {}; Stack treeStack; CoxGroup* W = 0; void activate(CommandTree* tree); void ambigAction(CommandTree* tree, const String& str); CommandData* ambigCommand(); void cellCompletion(DictCell* cell); void commandCompletion(DictCell* cell); void empty_error(char* str); CommandTree* emptyCommandTree(); template CommandTree* initCommandTree(); void printCommandTree(FILE* file, DictCell* cell); void startup(); void interface_entry(); void interface_exit(); void main_entry(); void main_exit(); void uneq_entry(); void uneq_exit(); void author_f(); void betti_f(); void coatoms_f(); void compute_f(); void descent_f(); void duflo_f(); void extremals_f(); void fullcontext_f(); void help_f(); void ihbetti_f(); void inorder_f(); void interface_f(); void invpol_f(); void klbasis_f(); void lcorder_f(); void lcells_f(); void lcwgraphs_f(); void lrcorder_f(); void lrcells_f(); void lrcwgraphs_f(); void lrwgraph_f(); void lwgraph_f(); void matrix_f(); void mu_f(); void not_implemented_f(); void pol_f(); void q_f(); void qq_f(); void rank_f(); void rcorder_f(); void rcells_f(); void rcwgraphs_f(); void rwgraph_f(); void schubert_f(); void show_f(); void showmu_f(); void slocus_f(); void sstratification_f(); void type_f(); void uneq_f(); const char* author_tag = "prints a message about the author"; const char* betti_tag = "prints the ordinary betti numbers"; const char* coatoms_tag = "prints out the coatoms of an element"; const char* compute_tag = "prints out the normal form of an element"; const char* descent_tag = "prints out the descent sets"; const char* duflo_tag = "prints out the Duflo involutions"; const char* extremals_tag = "prints out the k-l polynomials for the extremal pairs"; const char* fullcontext_tag = "sets the context to the full group"; const char* help_tag = "enters help mode"; const char* ihbetti_tag = "prints the IH betti numbers"; const char* input_tag = "(in help mode only) explains the input conventions"; const char* interface_tag = "changes the interface"; const char* intro_tag = "(in help mode only) prints a message for first time users"; const char* inorder_tag = "tells whether two elements are in Bruhat order"; const char* invpol_tag = "prints a single inverse k-l polynomial"; const char* klbasis_tag = "prints an element of the k-l basis"; const char* lcorder_tag = "prints the left cell order"; const char* lcells_tag = "prints out the left k-l cells"; const char* lcwgraphs_tag = "prints out the W-graphs of the left k-l cells"; const char* lrcorder_tag = "prints the two-sided cell order"; const char* lrcells_tag = "prints out the tow-sided k-l cells"; const char* lrcwgraphs_tag = "prints out the W-graphs of the two-sided k-l cells"; const char* lrwgraph_tag = "prints out the two-sided W-graph"; const char* lwgraph_tag = "prints out the left W-graph"; const char* matrix_tag = "prints the current Coxeter matrix"; const char* mu_tag = "prints a single mu-coefficient"; const char* pol_tag = "prints a single k-l polynomial"; const char* q_tag = "exits the current mode"; const char* qq_tag = "exits the program"; const char* rank_tag = "resets the rank"; const char* rcorder_tag = "prints the right cell order"; const char* rcells_tag = "prints out the right k-l cells"; const char* rcwgraphs_tag = "prints out the W-graphs of the right k-l cells"; const char* rwgraph_tag = "prints out the right W-graph"; const char* schubert_tag = "prints out the kl data for a schubert variety"; const char* show_tag = "maps out the computation of a k-l polynomial"; const char* showmu_tag = "maps out the computation of a mu coefficient"; const char* slocus_tag = "prints the rational singular locus of the Schubert variety"; const char* sstratification_tag = "prints the rational singular stratification of the Schubert variety"; const char* type_tag = "resets the type and rank (hence restarts the program)"; const char* uneq_tag = "puts the program in unequal-parameter mode"; namespace uneq { void klbasis_f(); void lcorder_f(); void lrcorder_f(); void lcells_f(); void lrcells_f(); void mu_f(); void pol_f(); void rcells_f(); void rcorder_f(); const char* lcorder_tag = "prints the left cell order"; const char* lrcorder_tag = "prints the two-sided cell order"; const char* lcells_tag = "prints out the left k-l cells"; const char* lrcells_tag = "prints out the two-sided k-l cells"; const char* mu_tag = "prints out a mu-coefficient"; const char* pol_tag = "prints out a single k-l polynomial"; const char* rcells_tag = "prints out the right k-l cells"; const char* rcorder_tag = "prints the right cell order"; }; }; namespace commands { void (*default_help)() = &help::default_h; }; namespace commands { namespace interface { GroupEltInterface* in_buf = 0; struct In_tag {}; struct Out_tag {}; void in_entry(); void in_exit(); void out_entry(); void out_exit(); void abort_f(); void alphabetic_f(); void bourbaki_f(); void default_f(); void decimal_f(); void gap_f(); void hexadecimal_f(); void in_f(); void out_f(); void permutation_f(); void symbol_f(); void terse_f(); void ordering_f(); const char* abort_tag = "leaves without modifying the interface"; const char* alphabetic_tag = "sets alphabetic generator symbols"; const char* bourbaki_tag = "sets Bourbaki conventions for i/o"; const char* decimal_tag = "sets decimal generator symbols"; const char* default_tag = "sets i/o to default mode"; const char* gap_tag = "sets i/o to GAP mode"; const char* hexadecimal_tag = "sets hexadecimal generator symbols"; const char* in_tag = "enters reset-input mode"; const char* out_tag = "enters reset-output mode"; const char* permutation_tag = "sets permutation notation for i/o (in type A only)"; const char* ordering_tag = "modifies the ordering of the generators"; const char* terse_tag = "sets i/o to terse mode"; namespace in { void alphabetic_f(); void bourbaki_f(); void decimal_f(); void default_f(); void gap_f(); void hexadecimal_f(); void permutation_f(); void postfix_f(); void prefix_f(); void separator_f(); void terse_f(); const char* alphabetic_tag = "sets alphabetic generator symbols for input"; const char* bourbaki_tag = "sets Bourbaki conventions for input"; const char* decimal_tag = "sets decimal generator symbols for input"; const char* default_tag = "sets default conventions for input"; const char* gap_tag = "sets GAP conventions for input"; const char* hexadecimal_tag = "sets hexadecimal generator symbols for input"; const char* permutation_tag = "sets permutation notation for input (in type A only)"; const char* postfix_tag = "resets the input postfix"; const char* prefix_tag = "resets the input prefix"; const char* separator_tag = "resets the input separator"; const char* symbol_tag = "resets an input symbol"; const char* terse_tag = "sets terse conventions for input"; }; namespace out { void alphabetic_f(); void bourbaki_f(); void decimal_f(); void default_f(); void gap_f(); void hexadecimal_f(); void permutation_f(); void postfix_f(); void prefix_f(); void separator_f(); void terse_f(); const char* alphabetic_tag = "sets alphabetic generator symbols for output"; const char* bourbaki_tag = "sets Bourbaki conventions for output"; const char* decimal_tag = "sets decimal generator symbols for output"; const char* default_tag = "sets default conventions for output"; const char* gap_tag = "sets GAP conventions for output"; const char* hexadecimal_tag = "sets hexadecimal generator symbols for output"; const char* permutation_tag = "sets permutation notation for output (in type A only)"; const char* postfix_tag = "resets the output postfix"; const char* prefix_tag = "resets the output prefix"; const char* separator_tag = "resets the output separator"; const char* symbol_tag = "resets an output symbol"; const char* terse_tag = "sets terse conventions for output"; }; }; }; /***************************************************************************** This module contains the code for the command interface. Although overall I'm happy with the way it works, it suffers from a certain amount of clumsiness. The idea is that at each point in time, there is a certain active CommandTree object. This is basically a dictionary of recognized command names, together with the functions that will executed for them; in other words, something that should be a map in STL parlance. Actually, the active command tree is the top of the command tree stack treeStack; exiting the current mode means popping the stack; entering a new mode means pushing it on the stack. Each mode has an associated entry and exit function, which take care of initialization and clean-up duties. Actually, there is mostly one main mode; the entry function for this is the one which gets type and rank for the user; the exit function destroys the current group. Redefining type or rank means exiting and re-entering the main mode. In addition, there is the "empty" mode, active on startup only, where nothing is defined yet, and some auxiliary modes which temporarily hide the main mode in order to perform certain duties : interface mode to set the i/o preferences of the user, help mode for help, and also unequal-parameter mode which sets unequal parameters for the k-l functions; this is in fact a sort of duplicate main mode. Command completion is implemented to the extend that incomplete commands are recognized when non-ambiguous. *****************************************************************************/ /***************************************************************************** Chapter I -- Running the program This section contains the following functions : - ambigAction(str) : what to do with an ambiguous command; - mainCommandTree() : returns a pointer to the initial command tree (and builds it on first call); - relax_f() : does nothing; - run() : runs an interactive session; *****************************************************************************/ namespace commands { void relax_f() /* Does nothing. */ {} void run() /* This function runs an interactive session of the program. */ { static String name(0); activate(emptyCommandTree()); if (ERRNO) { Error (ERRNO); return; } while (1) { /* the only way to exit from this loop is the "qq" command */ CommandTree* tree = treeStack.top(); tree->prompt(); getInput(stdin,name); CommandData* cd = tree->find(name); if (cd == 0) { tree->error(name.ptr()); continue; } if (cd == ambigCommand()) { ambigAction(tree,name); continue; } cd->action(); if (cd->autorepeat) { tree->setAction("",cd->action); tree->setRepeat("",true); } else { tree->setAction("",&relax_f); tree->setRepeat("",false); } } } void default_error(char* str) /* Default response to an unknown command. */ { Error(COMMAND_NOT_FOUND,str); return; } }; namespace { void activate(CommandTree* tree) /* Puts the tree on top of treeStack, and executes the initialization function. */ { treeStack.push(tree); tree->entry(); if (ERRNO) { /* an error occured during initialization */ Error(ERRNO); treeStack.pop(); ERRNO = MODECHANGE_FAIL; } return; } void ambigAction(CommandTree* tree, const String& str) /* Response to ambiguous commands. Prints a warning and the list of possible completions in the current tree on stderr. */ { static String name(0); bool b = true; print(stderr,str); fprintf(stderr," : ambiguous ("); DictCell* cell = tree->findCell(str); new(&name) String(str); printExtensions(stderr,cell->left,name,b); fprintf(stderr,")\n"); return; } void empty_error(char* str) { CommandTree* tree = mainCommandTree(); CommandData* cd = tree->find(str); if (cd == 0) { default_error(str); return; } if (cd == ambigCommand()) { ambigAction(tree,str); return; } activate(tree); if (ERRNO) { /* something went wrong during initialization */ Error(ERRNO); return; } /* type and rank are set at this point */ if ((cd != tree->find("type")) && (cd != tree->find("rank"))) cd->action(); if (cd->autorepeat) { tree->setAction("",cd->action); tree->setRepeat("",true); } else { tree->setAction("",&relax_f); tree->setRepeat("",false); } return; } void startup() /* The response to the first carriage return. Sets the response to "help" to a less verbose version, and starts up the program. */ { activate(mainCommandTree()); if (ERRNO) Error(ERRNO); return; } }; /***************************************************************************** Chapter II -- The CommandTree class. The purpose of a CommandTree is to get a command-name from the user (or perhaps from a file), and execute the corresponding command. For this, it maintains a tree of CommandCell s, one for each initial subword of each recognized command. Each CommandCell knows which command it should execute. Recognizing initial subwords allows for command completion : when the completion is unique, the command is executed as if the full name were typed. When the completion is not unique, the function for ambiguous commands is executed : as defined here, it prints the list of all possible completions in the current tree, and prompts the user again. The case of the empty command is special : either it does nothing, or, for most commands, it repeats the previous command. This setup supports the concept of mode : at all times, there is a current command tree, and in some situations this will change : new commands can become available, commands can change behaviour or can become unavailable. Help mode is an example of this. Another example is the interface command, which loads the interface mode tree, so that the user can set the various i/o parameters. NOTE : even though I like the actual behaviour of the setup, it is all rather clumsy and should be re-done. The command tree could be replaced with some associative container like map. The current behaviour could be pretty much kept as is, until we include the functionalities of readline. The following functions are defined : - constructors and destructors : - CommandTree(prompt,a,entry,error,exit,h) : builds a command tree with the given prompt, action a, help function h, given entry and exit functions, and error function (called when a command is not found); - ~CommandTree(); - accessors : - prompt : prints the prompt; - manipulators : - add(name,tag,a,h,rep) : adds a command with the given name, tag (used in the online help), action a, help-action h and repetition flag rep; - setAction(str,a) : resets the action of the command for str; - setRepeat(str,b) : resets the repetition flag of the command for b; ******************************************************************************/ namespace commands { CommandTree::CommandTree(const char* prompt, void (*a)(), void (*entry)(), void (*error)(char*), void (*exit)(), void (*h)()) :d_prompt(prompt), d_entry(entry), d_error(error), d_exit(exit) /* Initializes a command tree with the given prompt and action for the empty command. */ { d_root->ptr = new CommandData("","",a,&relax_f,false); if (h) { /* add help functionality */ d_help = new CommandTree("help",&cr_h,h); d_help->add("q",q_tag,&q_f,0,false); add("help",help_tag,&help_f,&help_h,false); } } CommandTree::~CommandTree() /* The memory allocated by a CommandTree object is hidden in the dictionary and in the d_help pointer. */ { delete d_help; } /******** accessors *********************************************************/ void CommandTree::prompt() const /* Prints the prompt for the command tree. */ { printf("%s : ",d_prompt.ptr()); } /******** manipulators ******************************************************/ void CommandTree::add(const char* name, const char* tag, void (*a)(), void (*h)(), bool rep) /* This function adds a new command to the tree, adding new cells as necessary. */ { CommandData *cd = new CommandData(name,tag,a,h,rep); insert(name,cd); if (d_help && h) { /* add help functionality */ d_help->add(name,tag,h,0,false); } } void CommandTree::setAction(const char* str, void (*a)()) /* Assuming that str is a fullname on the command tree, sets the response to str to a. NOTE : is a bit dangerous. Should work also when str is only a prefix. */ { CommandData* cd = find(str); cd->action = a; return; } void CommandTree::setRepeat(const char* str, bool b) /* Assuming that str is a fullname on the command tree, sets the autorepeat value of the corresponding command data structure to b. */ { CommandData* cd = find(str); cd->autorepeat = b; return; } }; /***************************************************************************** Chapter III -- The CommandData class. The CommandData structure collects the data associated to a given command name. The function a defines the action associated with the command; the function h defines the action associated with the command in help mode. The flag b is set if the command should be repeated on a carriage return. *****************************************************************************/ namespace commands { CommandData::CommandData(const char* const& str, const char* const& t, void (*a)(), void (*h)(), bool rep) :name(str), tag(t), action(a), help(h), autorepeat(rep) {} CommandData::~CommandData() /* No memory is allocated directly */ {} }; /***************************************************************************** Chapter IV -- Building the command tree This section contains the functions used for the construction of the primary command tree, i.e., the initialization of the command module. The following functions are defined : - ambigCommand() : returns a special value flagging ambiguous commands; - cellCompletion(cell) : auxiliary to commandCompletion; - commandCompletion(tree) : finishes off the command tree; - emptyCommandTree() : returns a pointer to the initial command tree; - initCommandTree : builds the empty command tree; - initCommandTree : builds the interface command tree; - initCommandTree : builds the main command tree; - initCommandTree : builds the command tree for unequal parameters; - interfaceCommandTree() : returns a pointer to the interface command tree; - mainCommandTree() : returns a pointer to the main command tree; - uneqCommandTree() : returns a pointer to the unequal-parameter command tree; *****************************************************************************/ namespace { CommandData* ambigCommand() /* Returns a dummy command cell which is a placeholder indicating that ambigAction must be executed; this requires knowledge of where we are in the command tree. */ { static CommandData cd("","",0,0,false); return &cd; } void cellCompletion(DictCell* cell) /* This function fills in the value fields of the cells which do not correspond to full names. It is assumed that the tree is traversed in infix (?) order, i.e. first visit left child, then cell, the right child, so that all longer names are already visited. This allows to fill in unique completions backwards, making thins easy. */ { if (cell->fullname == true) return; if (cell->uniquePrefix == false) { /* ambiguous */ cell->ptr = ambigCommand(); return; } if (cell->uniquePrefix == true) { /* unique completion */ cell->ptr = cell->left->value(); return; } } void commandCompletion(DictCell* cell) /* This function finishes up the command tree by implementing command completion. This is done as follows. We traverse the command tree from the root. If node.fullname is true, we do nothing. Otherwise, if node.uniquePrefix is true, we set node.value to be equal to the value of the unique completion of the string recognized by node in the dictionary. If node.uniquePrefix is false, we set node.value to ambigCommand(). */ { if (cell == 0) return; commandCompletion(cell->left); cellCompletion(cell); commandCompletion(cell->right); } template<> CommandTree* initCommandTree() /* This function builds the initial command tree of the program. The idea is that all commands on the main command tree will be considered entry commands, and so will do the necessary initialization. This is achieved thru the special error function. */ { static CommandTree tree("empty",&startup,&relax_f,&empty_error,&relax_f, &intro_h); tree.add("author","author_tag",&author_f,&relax_f,false); tree.add("qq",qq_tag,&qq_f,&qq_h,false); commandCompletion(tree.root()); tree.helpMode()->add("intro",intro_tag,&intro_h,0,false); commandCompletion(tree.helpMode()->root()); return &tree; } CommandTree* emptyCommandTree() /* Returns a pointer to the initial command tree of the program, building it on the first call. */ { static CommandTree* tree = initCommandTree(); return tree; } template<> CommandTree* initCommandTree() /* This function builds the interface command tree; this makes available the various little commands that are needed to reset the interface, and that have no reason to be clogging up the main command tree. */ { static CommandTree tree("interface",&relax_f,&interface_entry,&default_error, &interface_exit,&interface_help); tree.add("alphabetic",commands::interface::alphabetic_tag, &commands::interface::alphabetic_f,&help::interface::alphabetic_h); tree.add("bourbaki",commands::interface::bourbaki_tag, &commands::interface::bourbaki_f,&help::interface::bourbaki_h); tree.add("decimal",commands::interface::decimal_tag, &commands::interface::decimal_f,&help::interface::decimal_h); tree.add("default",commands::interface::default_tag, &commands::interface::default_f,&help::interface::default_h); tree.add("gap",commands::interface::out::gap_tag, &commands::interface::out::gap_f, &help::interface::gap_h); tree.add("hexadecimal",commands::interface::hexadecimal_tag, &commands::interface::hexadecimal_f, &help::interface::hexadecimal_h); tree.add("in",commands::interface::in_tag,&commands::interface::in_f, help::interface::in_h,false); tree.add("ordering",commands::interface::ordering_tag, &commands::interface::ordering_f,help::interface::ordering_h,false); tree.add("out",commands::interface::out_tag,&commands::interface::out_f, help::interface::out_h,false); tree.add("permutation",commands::interface::permutation_tag, &commands::interface::permutation_f, &help::interface::permutation_h); tree.add("q",q_tag,&q_f,0,false); tree.add("terse",commands::interface::out::terse_tag, &commands::interface::out::terse_f, &help::interface::out::terse_h); commandCompletion(tree.root()); commandCompletion(tree.helpMode()->root()); return &tree; } template<> CommandTree* initCommandTree() /* This function builds the command tree for the input-modification mode. */ { using namespace commands::interface; static CommandTree tree("in",&relax_f,&in_entry,&default_error, &in_exit,&help::interface::in_help); tree.add("q",q_tag,&q_f,0,false); tree.add("abort",abort_tag,&abort_f,&help::interface::abort_h); tree.add("alphabetic",in::alphabetic_tag,&in::alphabetic_f, &help::interface::in::alphabetic_h,false); tree.add("bourbaki",in::bourbaki_tag,&in::bourbaki_f, &help::interface::in::bourbaki_h); tree.add("decimal",in::decimal_tag,&in::decimal_f, &help::interface::in::decimal_h,false); tree.add("default",in::default_tag,&in::default_f, &help::interface::in::default_h); tree.add("gap",in::gap_tag,&in::gap_f,&help::interface::in::gap_h); tree.add("hexadecimal",in::hexadecimal_tag,&in::hexadecimal_f, &help::interface::in::hexadecimal_h,false); tree.add("permutation",in::permutation_tag,&in::permutation_f, &help::interface::in::permutation_h,false); tree.add("postfix",in::postfix_tag,&in::postfix_f, &help::interface::in::postfix_h); tree.add("prefix",in::prefix_tag,&in::prefix_f, &help::interface::in::prefix_h); tree.add("separator",in::separator_tag, &in::separator_f,&help::interface::in::separator_h); tree.add("symbol",in::symbol_tag,&symbol_f, &help::interface::in::symbol_h); tree.add("terse",in::terse_tag,&in::terse_f,&help::interface::in::terse_h); commandCompletion(tree.root()); commandCompletion(tree.helpMode()->root()); return &tree; } template<> CommandTree* initCommandTree() /* This function builds the command tree for the output-modification mode. */ { using namespace commands::interface; static CommandTree tree("out",&relax_f,&out_entry,&default_error, &out_exit,&help::interface::out_help); tree.add("q",q_tag,&q_f,0,false); tree.add("alphabetic",out::alphabetic_tag,&out::alphabetic_f, &help::interface::out::alphabetic_h,false); tree.add("bourbaki",out::bourbaki_tag,&out::bourbaki_f, &help::interface::out::bourbaki_h); tree.add("decimal",out::decimal_tag,&out::decimal_f, &help::interface::out::decimal_h,false); tree.add("default",out::default_tag,&out::default_f, &help::interface::out::default_h); tree.add("gap",out::gap_tag,&out::gap_f, &help::interface::out::gap_h); tree.add("hexadecimal",out::hexadecimal_tag,&out::hexadecimal_f, &help::interface::out::hexadecimal_h,false); tree.add("permutation",out::permutation_tag,&out::permutation_f, &help::interface::out::permutation_h,false); tree.add("postfix",out::postfix_tag,&out::postfix_f, &help::interface::out::postfix_h); tree.add("prefix",out::prefix_tag,&out::prefix_f, &help::interface::out::prefix_h); tree.add("separator",out::separator_tag, &out::separator_f,&help::interface::out::separator_h); tree.add("symbol",out::symbol_tag,&symbol_f, &help::interface::out::symbol_h); tree.add("terse",out::terse_tag,&out::terse_f, &help::interface::out::terse_h); commandCompletion(tree.root()); commandCompletion(tree.helpMode()->root()); return &tree; } }; namespace commands { CommandTree* interface::inCommandTree() { static CommandTree* tree = initCommandTree(); return tree; } CommandTree* interface::outCommandTree() { static CommandTree* tree = initCommandTree(); return tree; } CommandTree* interfaceCommandTree() /* Returns a pointer to the interface command tree, building it on the first call. */ { static CommandTree* tree = initCommandTree(); return tree; } }; namespace { template<> CommandTree* initCommandTree() /* This function builds the main command tree, the one that is being run on startup. Auxiliary trees may be grafted onto this one (thru the pushdown stack treeStack) by some functions needing to be in special modes. */ { static CommandTree tree("coxeter",&relax_f,&main_entry,&default_error, &main_exit,&main_help); tree.add("author",author_tag,&author_f,&relax_f,false); tree.add("betti",betti_tag,&betti_f,&betti_h,false); tree.add("coatoms",coatoms_tag,&coatoms_f,&coatoms_h); tree.add("compute",compute_tag,&compute_f,&compute_h); tree.add("descent",descent_tag,&descent_f,&descent_h); tree.add("duflo",duflo_tag,&duflo_f,&duflo_h); tree.add("extremals",extremals_tag,&extremals_f,&extremals_h); tree.add("fullcontext",fullcontext_tag,&fullcontext_f,&fullcontext_h); tree.add("ihbetti",ihbetti_tag,&ihbetti_f,&ihbetti_h,false); tree.add("interface",interface_tag,&interface_f,&interface_h,false); tree.add("inorder",inorder_tag,&inorder_f,&inorder_h); tree.add("invpol",invpol_tag,&invpol_f,&invpol_h); tree.add("lcorder",lcorder_tag,&lcorder_f,&lcorder_h,false); tree.add("lcells",lcells_tag,&lcells_f,&lcells_h,false); tree.add("lcwgraphs",lcwgraphs_tag,&lcwgraphs_f,&lcwgraphs_h,false); tree.add("lrcorder",lrcorder_tag,&lrcorder_f,&lrcorder_h,false); tree.add("lrcells",lrcells_tag,&lrcells_f,&lrcells_h,false); tree.add("lrcwgraphs",lrcwgraphs_tag,&lrcwgraphs_f,&lrcwgraphs_h,false); tree.add("lrwgraph",lrwgraph_tag,&lrwgraph_f,&lrwgraph_h,false); tree.add("lwgraph",lwgraph_tag,&lwgraph_f,&lwgraph_h,false); tree.add("klbasis",klbasis_tag,&klbasis_f,&klbasis_h,true); tree.add("matrix",matrix_tag,&matrix_f,&matrix_h); tree.add("mu",mu_tag,&mu_f,&mu_h); tree.add("pol",pol_tag,&pol_f,&pol_h); tree.add("q",q_tag,&q_f,0,false); tree.add("qq",qq_tag,&qq_f,&qq_h,false); tree.add("rank",rank_tag,&rank_f,&rank_h,false); tree.add("rcorder",rcorder_tag,&rcorder_f,&rcorder_h,false); tree.add("rcells",rcells_tag,&rcells_f,&rcells_h,false); tree.add("rcwgraphs",rcwgraphs_tag,&rcwgraphs_f,&rcwgraphs_h,false); tree.add("rwgraph",rwgraph_tag,&rwgraph_f,&rwgraph_h,false); tree.add("schubert",schubert_tag,&schubert_f,&schubert_h); tree.add("show",show_tag,&show_f,&show_h); tree.add("showmu",showmu_tag,&showmu_f,&showmu_h); tree.add("slocus",slocus_tag,&slocus_f,&slocus_h); tree.add("sstratification",sstratification_tag,&sstratification_f, &sstratification_h); tree.add("type",type_tag,&type_f,&type_h,false); tree.add("uneq",uneq_tag,&uneq_f,&uneq_h,false); special::addSpecialCommands(&tree); commandCompletion(tree.root()); tree.helpMode()->add("intro",intro_tag,&intro_h,0,false); tree.helpMode()->add("input",input_tag,&input_h,0,false); commandCompletion(tree.helpMode()->root()); return &tree; } }; namespace commands { CommandTree* mainCommandTree() /* Returns a pointer to the main command tree of the program, building it on the first call. */ { static CommandTree* tree = initCommandTree(); return tree; } }; namespace { template<> CommandTree* initCommandTree() /* This function builds the unequal-parameter command tree. It contains essentially the same functions as the main command tree, except that the unequal-parameter versions have been substituted for the k-l functions. */ { static CommandTree tree("uneq",&relax_f,&uneq_entry,&default_error, &uneq_exit,&uneq_help); tree.add("author",author_tag,&author_f,&relax_f,false); tree.add("coatoms",coatoms_tag,&coatoms_f,&coatoms_h); tree.add("compute",compute_tag,&compute_f,&compute_h); tree.add("descent",descent_tag,&descent_f,&descent_h); tree.add("fullcontext",fullcontext_tag,&fullcontext_f,&fullcontext_h); tree.add("interface",interface_tag,&interface_f,&interface_h,false); tree.add("klbasis",klbasis_tag,&uneq::klbasis_f,&help::uneq::klbasis_h,true); tree.add("lcorder",uneq::lcorder_tag,&uneq::lcorder_f, &help::uneq::lcorder_h,false); tree.add("lrcorder",uneq::lrcorder_tag,&uneq::lrcorder_f, &help::uneq::lrcorder_h,false); tree.add("lcells",uneq::lcells_tag,&uneq::lcells_f,&help::uneq::lcells_h, false); tree.add("lrcells",uneq::lrcells_tag,&uneq::lrcells_f,&help::uneq::lrcells_h, false); tree.add("matrix",matrix_tag,&matrix_f,&matrix_h); tree.add("mu",uneq::mu_tag,&uneq::mu_f,&help::uneq::mu_h); tree.add("pol",uneq::pol_tag,&uneq::pol_f,&help::uneq::pol_h); tree.add("rcells",uneq::rcells_tag,&uneq::rcells_f,&help::uneq::rcells_h, false); tree.add("rcorder",uneq::rcorder_tag,&uneq::rcorder_f, &help::uneq::rcorder_h,false); tree.add("q",q_tag,&q_f,0,false); tree.add("qq",qq_tag,&qq_f,&qq_h,false); commandCompletion(tree.root()); commandCompletion(tree.helpMode()->root()); return &tree; } }; namespace commands { CommandTree* uneqCommandTree() /* Returns a pointer to the uneq command tree, building it on the first call. */ { static CommandTree* tree = initCommandTree(); return tree; } }; /***************************************************************************** Chapter V -- Functions for the predefined commands. This section contains the functions defining the responses to the various commands which are provided by the program. The functions are placed in the unnamed namespace defined in this file. The following functions are defined : - author_f() : response to "author"; - betti_f() : response to "betti"; - coatoms_f() : response to "coatoms"; - compute_f() : response to "compute"; - descent_f() : response to "descent"; - duflo_f() : response to "duflo"; - extremals_f() : response to "extremals"; - fullcontext_f() : response to "fullcontext"; - ihbetti_f() : response to "ihbetti"; - inorder_f() : response to "inorder"; - interface_f() : response to "interface"; - help_f() : repsonse to "help"; - klbasis_f() : response to "klbasis"; - lcorder_f() : response to "lcorder"; - lcells_f() : response to "lcells"; - lcwgraphs_f() : response to "lcwgraphs"; - lrcorder_f() : response to "lrcorder"; - lrcells_f() : response to "lrcells"; - lrcwgraphs_f() : response to "lrcwgraphs"; - lrwgraph_f() : response to "lrwgraph"; - lwgraph_f() : response to "lwgraph"; - matrix_f() : response to "matrix"; - mu_f() : response to "mu"; - not_implemented_f() : response for not (yet) implemented features; - q_f() : response to "q"; - qq_f() : response to "qq"; - rank_f() : response to "rank"; - rcorder_f() : response to "rcorder"; - rcells_f() : response to "rcells"; - rcwgraphs_f() : response to "rcwgraphs"; - rwgraph_f() : response to "rwgraph"; - relax_f() : does nothing; - schubert_f() : response to "schubert"; - show_f() : response to "show"; - showmu_f() : response to "showmu"; - slocus_f() : response to "slocus"; - sstratification_f() : response to "sstratification"; - type_f() : response to "type"; - uneq_f() : response to "uneq"; In uneq mode : - klbasis_f() : response to "klbasis"; - lcorder_f() : response to "lcorder"; - lcells_f() : response to "lcells"; - lrcorder_f() : response to "lrcorder"; - lrcells_f() : response to "lrcells"; - mu_f() : response to "mu"; - pol_f() : response to "pol"; - rcells_f() : response to "rcells"; - rcorder_f() : response to "rcorder"; In interface mode : - abort_f() : aborts input interface modification; - alphabetic_f() : sets alphabetic generator symbols; - bourbaki_f() : sets bourbaki conventions; - decimal_f() : sets decimal generator symbols; - default_f() : sets default i/o; - gap_f() : sets GAP-style i/o; - hexadecimal_f() : sets hexadecimal generator symbols; - ordering_f() : changes the ordering of the generators; - symbol_f() : resets generator symbol; - terse_f() : sets terse style i/o; - in::alphabetic_f() : sets alphabetic generator symbols; - in::bourbaki_f() : sets bourbaki conventions; - in::decimal_f() : sets decimal generator symbols; - in::default_f() : sets default-style input; - in::gap_f() : sets GAP-style input; - in::hexadecimal_f() : sets hexadecimal generator symbols; - in::permutation_f() : sets permutation input; - in::postfix_f() : resets input postfix; - in::prefix_f() : resets input prefix; - in::separator_f() : resets input separator; - in::terse_f() : sets terse-style input; - out::alphabetic_f() : sets alphabetic generator symbols; - out::bourbaki_f() : sets bourbaki conventions; - out::decimal_f() : sets decimal generator symbols; - out::default_f() : sets default-style output; - out::gap_f() : sets GAP-style output; - out::hexadecimal_f() : sets hexadecimal generator symbols; - out::permutation_f() : sets permutation output; - out::postfix_f() : resets output postfix; - out::prefix_f() : resets output prefix; - out::separator_f() : resest output separator; - out::terse_f() : sets terse-style output; *****************************************************************************/ namespace { void author_f() /* Prints a message about the author. */ { printFile(stderr,"author.mess",MESSAGE_DIR); return; } void betti_f() /* Prints out the ordinary betti numbers of [e,y]. NOTE : could be *much* improved! In particular, we would want to have betti(x,y) for x <= y. */ { static CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } OutputTraits& traits = W->outputTraits(); printBetti(stdout,y,W->schubert(),traits); return; } void coatoms_f() /* Prints out the coatoms of a given element, computing them in elementary fashion. */ { static CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } List c(0); W->coatoms(c,g); for (Ulong j = 0; j < c.size(); ++j) { W->print(stdout,c[j]); printf("\n"); } return; } void compute_f() /* Gets an element from the user, and prints out its normal form. */ { static CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } W->normalForm(g); W->print(stdout,g); if (SmallCoxGroup* Ws = dynamic_cast (W)) { CoxNbr x = 0; Ws->prodD(x,g); printf(" (#%lu)",static_cast(x)); } CoxNbr x = W->contextNumber(g); if (x != undef_coxnbr) printf(" (%s%lu)","%",static_cast(x)); printf("\n"); return; } void descent_f() /* Prints the left and right descent sets. */ { static CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } LFlags f = W->ldescent(g); printf("L:"); W->printFlags(stdout,f); printf("; R:"); f = W->rdescent(g); W->printFlags(stdout,f); printf("\n"); return; } void duflo_f() /* Prints the Duflo involutions. Works for finite groups only. */ { if (!isFiniteType(W)) { printFile(stderr,"duflo.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),dufloH,traits); printDuflo(file.f(),Wf->duflo(),Wf->lCell(),Wf->kl(),W->interface(),traits); return; } void extremals_f() /* Prints out the list of extremal elements x <= y (this is part of the schubert command. */ { static CoxWord g(0); printf("Enter your element (finish with a carriage-return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } interactive::OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),extremalsH,traits); printExtremals(file.f(),y,W->kl(),W->interface(),traits); return; } void fullcontext_f() /* Response to the fullcontext command. This sets the context to the full group. Of course, it works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"fullcontext.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); } return; } void help_f() /* Response to the help command. */ { activate(treeStack.top()->helpMode()); return; } void ihbetti_f() /* Prints out the IH betti numbers of [e,y]. */ { static CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } OutputTraits& traits = W->outputTraits(); printIHBetti(stdout,y,W->kl(),traits); return; } void interface_f() /* Response to the interface command. */ { activate(interfaceCommandTree()); return; } void inorder_f() /* Response to the inorder command. This will tell whether two elements are comparable in Bruhat order, using only the elementary string operations (and hence not consuming any memory.) */ { CoxWord g(0); CoxWord h(0); List a(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); h = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } if (W->inOrder(a,g,h)) { fprintf(stdout,"true : "); Ulong i = 0; for (Ulong j = 0; j < a.size(); ++j) { while (i < a[j]) { W->printSymbol(stdout,h[i]-1); ++i; } fprintf(stdout,"."); ++i; } while (i < h.length()) { W->printSymbol(stdout,h[i]-1); ++i; } fprintf(stdout,"\n"); } else fprintf(stdout,"false\n"); } void invpol_f() /* Response to the invpol command. This prints out a single inverse k-l polynomial, without details. */ { CoxWord g(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } const invkl::KLPol& pol = W->invklPol(x,y); if (ERRNO) { Error(ERRNO,x,y); return; } print(stdout,pol,"q"); printf("\n"); return; } void klbasis_f() /* Prints out one element in the k-l basis of the group, in the format defined by the current output mode. */ { CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } kl::HeckeElt h(0); W->cBasis(h,y); if (ERRNO) { Error(ERRNO); return; } interactive::OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),basisH,traits); printAsBasisElt(file.f(),h,W->schubert(),W->interface(),traits); return; } void lcorder_f() /* Prints the left cell order of the current group in a file. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"lcorder.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lCOrderH,traits); printLCOrder(file.f(),Wf->kl(),Wf->interface(),traits); return; } void lcells_f() /* This function prints out the left cells in the group. */ { if (!isFiniteType(W)) { printFile(stderr,"lcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lCellsH,traits); printLCells(file.f(),Wf->lCell(),Wf->kl(),Wf->interface(),traits); return; } void lcwgraphs_f() /* This function prints out the W-graphs of the left cells in the group. It works only for finite groups currently. */ { if (!isFiniteType(W)) { printFile(stderr,"lcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lCellWGraphsH,traits); printLCellWGraphs(file.f(),Wf->lCell(),Wf->kl(),W->interface(),traits); return; } void lrcorder_f() /* Prints the two-sided cell order of the current group in a file. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"lrcorder.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lrCOrderH,traits); printLRCOrder(file.f(),Wf->kl(),Wf->interface(),traits); return; } void lrcells_f() /* This function prints out the two-sided cells in the group, together with the corresponding W-graphs. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"lrcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lrCellsH,traits); printLRCells(file.f(),Wf->lrCell(),Wf->kl(),Wf->interface(),traits); return; } void lrcwgraphs_f() /* This function prints out the W-graphs of the two-sided cells in the group. It works only for finite groups currently. */ { if (!isFiniteType(W)) { printFile(stderr,"lcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lrCellWGraphsH,traits); printLRCellWGraphs(file.f(),Wf->lrCell(),Wf->kl(),W->interface(),traits); return; } void lrwgraph_f() /* Prints out the two-sided wgraph of the current context. */ { if (!W->isFullContext() && wgraph_warning) { printFile(stderr,"wgraph.mess",MESSAGE_DIR); printf("continue ? y/n\n"); if (!yesNo()) return; printf("print this message next time ? y/n\n"); if (!yesNo()) wgraph_warning = false; } W->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),lrWGraphH,traits); printLRWGraph(file.f(),W->kl(),W->interface(),traits); return; } void lwgraph_f() /* Prints out the left wgraph of the current context. */ { if (!W->isFullContext() && wgraph_warning) { printFile(stderr,"wgraph.mess",MESSAGE_DIR); printf("continue ? y/n\n"); if (!yesNo()) return; printf("print this message next time ? y/n\n"); if (!yesNo()) wgraph_warning = false; } W->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),lWGraphH,traits); printLWGraph(file.f(),W->kl(),W->interface(),traits); return; } void matrix_f() /* Prints the Coxeter matrix. */ { interactive::printMatrix(stdout,W); return; } void not_implemented_f() /* Response for not (yet) implemented commands. */ { fprintf(stderr,"Sorry, not implemented yet\n"); return; } void mu_f() /* Response to the mu command. This prints out a single mu-coefficient, without details. */ { static CoxWord g(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } KLCoeff mu = W->mu(x,y); if (ERRNO) { Error(ERRNO,x,y); return; } printf("%lu\n",static_cast(mu)); return; } void pol_f() /* Response to the pol command. This prints out a single polynomial, without details. */ { static CoxWord g(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } const kl::KLPol& pol = W->klPol(x,y); if (ERRNO) { Error(ERRNO,x,y); return; } print(stdout,pol,"q"); printf("\n"); return; } void q_f() /* Exits the current mode. If there is a problem on exit, the exit function has the option of setting an error, thus preventing the exit. */ { CommandTree* tree = treeStack.top(); tree->exit(); if (ERRNO) { Error(ERRNO); return; } treeStack.pop(); return; } void qq_f() /* Exits the program. */ { while(treeStack.size()) { CommandTree* tree = treeStack.top(); tree->exit(); treeStack.pop(); } exit(0); } void rank_f() /* Sets the rank. */ { CoxGroup* Wloc = interactive::allocCoxGroup(W->type()); if (ERRNO) { Error(ERRNO); } else { W = Wloc; } return; } void rcorder_f() /* Prints the right cell order of the current group in a file. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"rcorder.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),rCOrderH,traits); printRCOrder(file.f(),Wf->kl(),Wf->interface(),traits); return; } void rcells_f() /* This function prints out the right cells in the group, together with the corresponding W-graphs. */ { if (!isFiniteType(W)) { printFile(stderr,"rcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),rCellsH,traits); printRCells(file.f(),Wf->rCell(),Wf->kl(),Wf->interface(),traits); return; } void rcwgraphs_f() /* This function prints out the W-graphs of the right cells in the group. It works only for finite groups currently. */ { if (!isFiniteType(W)) { printFile(stderr,"lcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),rCellWGraphsH,traits); printRCellWGraphs(file.f(),Wf->rCell(),Wf->kl(),W->interface(),traits); return; } void rwgraph_f() /* Prints out the right wgraph of the current context. */ { if (!W->isFullContext() && wgraph_warning) { printFile(stderr,"wgraph.mess",MESSAGE_DIR); printf("continue ? y/n\n"); if (!yesNo()) return; printf("print this message next time ? y/n\n"); if (!yesNo()) wgraph_warning = false; } W->fillMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),rWGraphH,traits); printRWGraph(file.f(),W->kl(),W->interface(),traits); return; } void schubert_f() /* Response to the schubert command. This will print out the information corresponding to one element in the k-l basis, and the information on the singularities of the corresponding Schubert variety, in the format popularized by Goresky. */ { static CoxWord g(0); printf("Enter your element (finish with a carriage-return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } interactive::OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),closureH,traits); printClosure(file.f(),y,W->kl(),W->interface(),traits); return; } void show_f() /* Response to the show command. This maps out the computation of a Kazhdan- Lusztig polynomial, letting you choose the descent generator. If no generator is given, the default descent generator is used. */ { static CoxWord g(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } fprintf(stdout,"generator (carriage return for default) : "); LFlags f = W->descent(y); Generator s = interactive::getGenerator(W,f); if (ERRNO) { Error (ERRNO); return; } interactive::OutputFile file; showKLPol(file.f(),W->kl(),x,y,W->interface(),s); return; } void showmu_f() /* Response to the showmu command. This maps out the computation of a mu-coefficient, letting you choose the descent generator. If no generator is given, the default descent generator is used. */ { static CoxWord g(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } interactive::OutputFile file; showMu(file.f(),W->kl(),x,y,W->interface()); return; } void slocus_f () /* Response to the slocus command. Prints out the singular locus of the Schubert variety cl(X_y). */ { static CoxWord g(0); printf("Enter your element (finish with a carriage-return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),slocusH,traits); printSingularLocus(file.f(),y,W->kl(),W->interface(),traits); return; } void sstratification_f () /* Response to the slocus command. Prints out the singular locus of the Schubert variety cl(X_y). */ { static CoxWord g(0); printf("Enter your element (finish with a carriage-return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),sstratificationH,traits); printSingularStratification(file.f(),y,W->kl(),W->interface(),traits); return; } void type_f() /* This function sets the type of W, i.e., gets a type and rank from the user and sets W to a new group of that type and rank. */ { CoxGroup* Wloc = interactive::allocCoxGroup(); if (ERRNO) { Error(ERRNO); } else { delete W; wgraph_warning = true; W = Wloc; } return; } void uneq_f() /* Response to the uneq command. */ { activate(uneqCommandTree()); return; } namespace uneq { void klbasis_f() /* Prints out one element in the k-l basis of the group, in the format defined by the current output mode. */ { CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } uneqkl::HeckeElt h(0); W->uneqcBasis(h,y); if (ERRNO) { Error(ERRNO); return; } interactive::OutputFile file; OutputTraits& traits = W->outputTraits(); printHeader(file.f(),basisH,traits); printAsBasisElt(file.f(),h,W->schubert(),W->interface(),traits); return; } void lcells_f() /* This function prints out the left cells in the group. */ { if (!isFiniteType(W)) { printFile(stderr,"lcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillUEMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lCellsH,traits); printLCells(file.f(),Wf->lUneqCell(),Wf->uneqkl(),Wf->interface(),traits); return; } void lcorder_f() /* Prints the left cell order of the closure of the current group in a file. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"lcorder.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillUEMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lCOrderH,traits); printLCOrder(file.f(),Wf->uneqkl(),Wf->interface(),traits); return; } void lrcorder_f() /* Prints the two-sided cell order of the closure of the current group in a file. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"uneq/lrcorder.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillUEMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lrCOrderH,traits); printLRCOrder(file.f(),Wf->uneqkl(),Wf->interface(),traits); return; } void lrcells_f() /* This function prints out the two-sided cells in the group. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"uneq/lrcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillUEMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),lrCellsH,traits); printLRCells(file.f(),Wf->lrUneqCell(),Wf->uneqkl(),Wf->interface(),traits); return; } void mu_f() /* Response to the "mu" command. Prints out a single mu-coefficient. When the generator s act on the left, we use the fact that mu(left_s,x,y) is equal to mu(right_s,x^{-1},y^{-1}) to go over to the right action. This is necessary because the mu-tables are kept only for right actions. */ { static CoxWord g(0); bool leftAction = false; fprintf(stdout,"generator : "); Generator s = getGenerator(W); if (s >= W->rank()) { // action is on the left s -= W->rank(); leftAction = true; } fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (leftAction) W->inverse(g); if (!W->isDescent(g,s)) { // mu(s,x,y) is undefined fprintf(stderr,"xs is greater than x\n"); return; } CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (leftAction) W->inverse(g); if (W->isDescent(g,s)) { // mu(s,x,y) is undefined fprintf(stderr,"ys is smaller than y\n"); return; } if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (x == y) { fprintf(stderr,"the two elements are equal\n"); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } const uneqkl::MuPol& mu = W->uneqmu(s,x,y); if (ERRNO) { Error(ERRNO,x,y); return; } print(stdout,mu,"v"); printf("\n"); return; } void pol_f() /* Response to the "pol" command. Prints out a single polynomial. */ { static CoxWord g(0); fprintf(stdout,"first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr x = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->extendContext(g); if (ERRNO) { Error(ERRNO); return; } if (!W->inOrder(x,y)) { fprintf(stderr,"the two elements are not in Bruhat order\n"); return; } const uneqkl::KLPol& pol = W->uneqklPol(x,y); if (ERRNO) { Error(ERRNO,x,y); return; } print(stdout,pol,"q"); printf("\n"); return; } void rcells_f() /* This function prints out the left cells in the group. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"rcells.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillUEMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),rCellsH,traits); printRCells(file.f(),Wf->rUneqCell(),Wf->uneqkl(),Wf->interface(),traits); return; } void rcorder_f() /* Prints the right cell order of the current group in a file. Works only for finite groups. */ { if (!isFiniteType(W)) { printFile(stderr,"rcorder.mess",MESSAGE_DIR); return; } FiniteCoxGroup* Wf = dynamic_cast (W); Wf->fullContext(); if (ERRNO) { Error(ERRNO); return; } Wf->fillUEMu(); if (ERRNO) { Error(ERRNO); return; } OutputFile file; OutputTraits& traits = Wf->outputTraits(); printHeader(file.f(),rCOrderH,traits); printRCOrder(file.f(),Wf->uneqkl(),Wf->interface(),traits); return; } }; }; namespace commands { void interface::abort_f() /* Aborts the interface modification. Bypasses the exit function, so that there is no further checking of the abandoned choices. */ { delete in_buf; in_buf = 0; treeStack.pop(); return; } void interface::alphabetic_f() /* Sets i/o to the standard alphabetic conventions : the symbols are the alphabetic sequence, prefix and postfix are empty, and the separator is "." iff the rank is > 26. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),Alphabetic()); W->interface().setIn(*in_buf); W->interface().setOut(*in_buf); return; } void interface::bourbaki_f() /* Sets Bourbaki conventions. This means that the ordering is reverted in types B and D, and symbols as well. NOTE : currently not implemented for affine groups. */ { delete in_buf; in_buf = new GroupEltInterface(W->interface().inInterface()); in::bourbaki_f(); W->interface().setIn(*in_buf); delete in_buf; in_buf = new GroupEltInterface(W->interface().outInterface()); out::bourbaki_f(); W->interface().setOut(*in_buf); return; } void interface::decimal_f() /* Sets i/o to the standard decimal conventions : the symbols are the decimal sequence, prefix and postfix are empty, and the separator is "." iff the rank is > 9. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),Decimal()); W->interface().setIn(*in_buf); W->interface().setOut(*in_buf); return; } void interface::default_f() /* Sets i/o settings to the default style. This means that we use decimal symbols, no prefix or postfix, and separator "." only when rank is >= 10. The ordering is the internal default ordering. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank()); W->interface().setIn(*in_buf); W->interface().setOut(*in_buf); W->interface().setOrder(identityOrder(W->rank())); W->interface().setDescent(Default()); W->setOutputTraits(Pretty()); return; } void interface::gap_f() /* Sets i/o settings to GAP style. This means first of all that Bourbaki conventions are adopted; decimal symbols are used for i/o with prefix "[", separator "," and postfix "]". Furthermore, output to files is done in GAP style, which produces files that are directly legible by GAP3. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),GAP()); in::bourbaki_f(); W->interface().setIn(*in_buf); out::bourbaki_f(); W->interface().setOut(*in_buf); W->interface().setDescent(GAP()); W->setOutputTraits(GAP()); return; } void interface::hexadecimal_f() /* Sets i/o to the standard hexadecimal conventions : the symbols are the hexadecimal sequence, prefix and postfix are empty, and the separator is "." iff the rank is > 15. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),Hexadecimal()); W->interface().setIn(*in_buf); W->interface().setOut(*in_buf); return; } void interface::in_f() { activate(inCommandTree()); return; } void interface::ordering_f() /* Allows the user to change the generator ordering. */ { static Permutation in_order(W->rank()); changeOrdering(W,in_order); if (ERRNO) { Error(ERRNO); return; } W->setOrdering(in_order); return; } void interface::out_f() { activate(outCommandTree()); return; } void interface::permutation_f() /* Activates permutation i/o. */ { using namespace typeA; if (!isTypeA(W->type())) { printFile(stderr,"permutation.mess",MESSAGE_DIR); return; } TypeACoxGroup* WA = dynamic_cast(W); WA->setPermutationInput(true); WA->setPermutationOutput(true); W->interface().setOrder(identityOrder(W->rank())); W->interface().setDescent(Default()); W->setOutputTraits(Pretty()); return; } void interface::symbol_f() /* Resets a symbol in in_buf (this will become either an input or an output symbol). */ { static String buf(0); const Interface& I = W->interface(); Generator s = undef_generator; reset(buf); do { if (ERRNO) Error(ERRNO); printf("enter the generator symbol you wish to change, ? to abort:\n"); getInput(stdin,buf,0); if (buf[0] == '?') return; io::skipSpaces(buf,0); Token tok; I.symbolTree().find(buf,0,tok); if (tokenType(tok) != generator_type)/* error */ ERRNO = NOT_GENERATOR; else s = tok-1; } while (ERRNO); printf("enter the new symbol (finish with a carriage return):\n"); getInput(stdin,buf,0); in_buf->setSymbol(s,buf); return; } void interface::terse_f() /* Sets i/o settings to terse style. This style is meant for outputting files that are easily parsed by computer. Th ordering of the generators is left untouched, and can be set independently by the user. Decimal output symbols are chosen, prefix is set to "[", postfix to "]" and separator to ",". */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),GAP()); W->interface().setIn(*in_buf); W->interface().setOut(*in_buf); W->interface().setDescent(Default()); W->setOutputTraits(Terse()); return; } void interface::in::alphabetic_f() /* Sets the input symbols to the alphabetic sequence. */ { const String* alpha = alphabeticSymbols(in_buf->symbol.size()); for (Ulong j = 0; j < in_buf->symbol.size(); ++j) { in_buf->symbol[j] = alpha[j]; } return; } void interface::in::bourbaki_f() /* Sets Bourbaki conventions for input. This means reverting the ordering of the input symbols in types B and D. */ { const Type& x = W->type(); if (!isFiniteType(x)) return; if (!(isTypeB(x) || isTypeD(x))) return; for (Generator s = 0; s < W->rank(); ++s) { in_buf->symbol[s] = W->interface().inSymbol(W->rank()-s-1); } return; } void interface::in::decimal_f() /* Sets the input symbols to the decimal sequence. */ { const String* dec = decimalSymbols(in_buf->symbol.size()); for (Ulong j = 0; j < in_buf->symbol.size(); ++j) { in_buf->symbol[j] = dec[j]; } return; } void interface::in::default_f() /* Sets the input interface to the default style. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank()); return; } void interface::in::gap_f() /* Sets the input interface to GAP style, and enforces Bourbaki conventions. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),GAP()); in::bourbaki_f(); return; } void interface::in::hexadecimal_f() /* Sets the input symbols to the hexadecimal sequence. */ { const String* hex = hexSymbols(in_buf->symbol.size()); for (Ulong j = 0; j < in_buf->symbol.size(); ++j) { in_buf->symbol[j] = hex[j]; } return; } void interface::in::permutation_f() /* Sets input to permutation mode (type A only.) */ { using namespace typeA; if (!isTypeA(W->type())) { printFile(stderr,"permutation.mess",MESSAGE_DIR); return; } TypeACoxGroup* WA = dynamic_cast(W); WA->setPermutationInput(true); delete in_buf; in_buf = 0; return; } void interface::in::postfix_f() /* Resets the input postfix. */ { printf("Enter the new input postfix (finish with a carriage return):\n"); String buf(0); getInput(stdin,buf,0); in_buf->setPostfix(buf); return; } void interface::in::prefix_f() /* Resets the input prefix. */ { printf("Enter the new input prefix (finish with a carriage return):\n"); String buf(0); getInput(stdin,buf,0); in_buf->setPrefix(buf); return; } void interface::in::separator_f() /* Resets the input separator. */ { printf("Enter the new input separator (finish with a carriage return):\n"); String buf(0); getInput(stdin,buf,0); in_buf->setSeparator(buf); return; } void interface::in::terse_f() /* Sets the input interface to terse style (the same as GAP style). */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),GAP()); return; } void interface::out::alphabetic_f() /* Changes the output symbols to hexadecimal. */ { const String* alpha = alphabeticSymbols(in_buf->symbol.size()); for (Ulong j = 0; j < in_buf->symbol.size(); ++j) { in_buf->symbol[j] = alpha[j]; } return; } void interface::out::bourbaki_f() /* Sets Bourbaki conventions for input. This means reverting the ordering of the output symbols in types B and D, and setting the output ordering to the reverse of the default one. */ { const Type& x = W->type(); if (!isFiniteType(x)) return; if (!(isTypeB(x) || isTypeD(x))) { W->setOrdering(identityOrder(W->rank())); return; } for (Generator s = 0; s < W->rank(); ++s) { in_buf->symbol[s] = W->interface().outSymbol(W->rank()-s-1); } Permutation a(W->rank()); for (Generator s = 0; s < W->rank(); ++s) { a[s] = W->rank()-1-s; } W->setOrdering(a); return; } void interface::out::decimal_f() /* Changes the output symbols to decimal. */ { const String* dec = decimalSymbols(in_buf->symbol.size()); for (Ulong j = 0; j < in_buf->symbol.size(); ++j) { in_buf->symbol[j] = dec[j]; } return; } void interface::out::default_f() /* Sets output styles to the default style. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank()); W->setOrdering(identityOrder(W->rank())); W->setOutputTraits(Pretty()); return; } void interface::out::gap_f() /* Sets output styles to GAP style, and enforces Bourbaki conventions. */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),GAP()); W->setOrdering(identityOrder(W->rank())); out::bourbaki_f(); W->interface().setDescent(GAP()); W->interface().setOut(*in_buf); // has to be done here so that output traits // will be correct. W->setOutputTraits(GAP()); return; } void interface::out::hexadecimal_f() /* Changes the output symbols to hexadecimal. */ { const String* hex = hexSymbols(in_buf->symbol.size()); for (Ulong j = 0; j < in_buf->symbol.size(); ++j) { in_buf->symbol[j] = hex[j]; } return; } void interface::out::permutation_f() /* Sets output to permutation mode (type A only.) */ { using namespace typeA; if (!isTypeA(W->type())) { printFile(stderr,"permutation.mess",MESSAGE_DIR); return; } TypeACoxGroup* WA = dynamic_cast(W); WA->setPermutationOutput(true); W->interface().setOrder(identityOrder(W->rank())); W->interface().setDescent(Default()); W->setOutputTraits(Pretty()); delete in_buf; in_buf = 0; return; } void interface::out::postfix_f() /* Resets the output postfix. */ { printf("enter the new output postfix (finish with a carriage return):\n"); String buf(0); getInput(stdin,buf,0); in_buf->setPostfix(buf); return; } void interface::out::prefix_f() /* Resets the output prefix. */ { printf("Enter the new output prefix (finish with a carriage return):\n"); String buf(0); getInput(stdin,buf,0); in_buf->setPrefix(buf); return; } void interface::out::separator_f() /* Resets the output separator. */ { printf("Enter the new output separator (finish with a carriage return):\n"); String buf(0); getInput(stdin,buf,0); in_buf->setSeparator(buf); return; } void interface::out::terse_f() /* Sets output styles to terse style (the same as GAP style). */ { delete in_buf; in_buf = new GroupEltInterface(W->rank(),GAP()); W->interface().setDescent(Default()); W->interface().setOut(*in_buf); // has to be done here so that output // traits will be correct W->setOutputTraits(Terse()); return; } }; /***************************************************************************** Chapter VI -- Miscellaneous. This section contains some auxiliary functions : - printCommands(file,tree) : prints info about the various commands on the tree; - printCommandTree(file,cell) : the recursive function doing the actual work; - interface_entry() : entry function for the interface mode; - interface_exit() : exit function for the interface mode; - interface::in_entry() : entry function for the interface::in mode; - interface::in_exit() : exit function for the interface::in mode; - interface::out_entry() : entry function for the interface::out mode; - interface::out_exit() : exit function for the interface::out mode; - main_entry() : entry function for the main mode; - main_exit() : exit function for the main mode; - uneq_entry() : entry function for the uneq mode; - uneq_exit() : exit function for the uneq mode; *****************************************************************************/ namespace commands { void printCommands(FILE* file, CommandTree* tree) /* Prints one line for each command on the tree (sorted in alphabetical order) with the name of the command and the information contained in the tag field. */ { printCommandTree(file,tree->root()->left); return; } }; CoxGroup* commands::currentGroup() /* Returns the "current" Coxeter group. NOTE : this will probably have to be refined in the future. */ { return W; } namespace { void printCommandTree(FILE* file, DictCell* cell) { if (cell == 0) return; if (cell->fullname) { /* print command info */ CommandData* cd = cell->value(); fprintf(file," - %s : %s;\n",cd->name.ptr(),cd->tag.ptr()); }; printCommandTree(file,cell->left); printCommandTree(file,cell->right); return; } void interface_entry() { commands::interface::in_buf = new GroupEltInterface(W->rank()); return; } void interface_exit() { delete commands::interface::in_buf; commands::interface::in_buf = 0; return; } void main_entry() /* Sets the type and rank. This is used as entry function for the main mode, and as the function that restarts the program when we change the type. NOTE : error handling should be done by the calling function. NOTE : something should be done about deallocating before reallocating! */ { W = interactive::allocCoxGroup(); /* an error may be set here */ return; } }; namespace commands { void interface::in_entry() /* Entry function to the input interface modification mode. The global variable in_buf is originally set to value for the current group. */ { Permutation a(W->interface().order()); a.inverse(); printf("current input symbols are the following :\n\n"); printInterface(stdout,W->interface().inInterface(),a); printf("\n"); in_buf = new GroupEltInterface(W->interface().inInterface()); return; } void interface::in_exit() /* Exit function from the input modification mode. It checks if the modifications made by the user are consistent with the ones that will remain from the old interface; if yes, it confirms the modifications and exits peacefully; if not, it prints out the problems and keeps the user in the mode. */ { if (in_buf == 0) // hack to prevent execution in special cases return; Permutation a(W->interface().order()); a.inverse(); /* at this point in_buf holds the full putative new interface; we need to check for reserved or repeated non-empty symbols */ const String* str = checkLeadingWhite(*in_buf); if (str) { Error(LEADING_WHITESPACE,in_buf,&W->interface().inInterface(),&a,str); goto error_exit; } str = checkReserved(*in_buf,W->interface()); if (str) { Error(RESERVED_SYMBOL,in_buf,&W->interface().inInterface(),&a,str); goto error_exit; } if (!checkRepeated(*in_buf)) { Error(REPEATED_SYMBOL,in_buf,&W->interface().inInterface(),&a); goto error_exit; } /* if we reach this point, the new interface is ok */ printf("new input symbols:\n\n"); printInterface(stdout,*in_buf,a); printf("\n"); W->interface().setIn(*in_buf); return; error_exit: ERRNO = ERROR_WARNING; return; } void interface::out_entry() /* Entry function to the output interface modification mode. The global variable in_buf is originally set to value for the current group. */ { delete in_buf; in_buf = new GroupEltInterface(W->interface().outInterface()); Permutation a(W->interface().order()); a.inverse(); printf("current output symbols are the following :\n\n"); printInterface(stdout,*in_buf,W->interface().inInterface(),a); printf("\n"); return; } void interface::out_exit() /* Exit function for the output modification mode. No checking is necessary here. */ { if (in_buf == 0) // hack to prevent execution in special cases return; Permutation a(W->interface().order()); a.inverse(); printf("new output symbols:\n\n"); printInterface(stdout,*in_buf,W->interface().inInterface(),a); printf("\n"); W->interface().setOut(*in_buf); return; } }; namespace { void main_exit() /* Symmetric function to main_entry. Should undo what main_entry did. */ { delete W; wgraph_warning = true; return; } void uneq_entry() { W->activateUEKL(); return; } void uneq_exit() /* We keep the unequal-parameter context, because one might want to go back and forth between the unequal and the ordinary case. */ { return; } }; positivity_final/commands.h0000600000175000017500000000645310011171251017601 0ustar duclouxducloux00000000000000/* This is commands.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef COMMANDS_H /* guard against multiple inclusions */ #define COMMANDS_H #include "globals.h" namespace commands { using namespace globals; }; #include "coxgroup.h" /******** type declarations ************************************************/ namespace commands { struct CommandData; class CommandTree; }; /******** constants ********************************************************/ namespace commands { extern void (*default_help)(); }; /******** function declarations ********************************************/ namespace commands { coxgroup::CoxGroup* currentGroup(); void default_error(char* str); void execute(); CommandTree* interfaceCommandTree(); CommandTree* mainCommandTree(); void printCommands(FILE* file, CommandTree* tree); void relax_f(); void run(); CommandTree* uneqCommandTree(); namespace interface { CommandTree* inCommandTree(); CommandTree* outCommandTree(); }; }; /******** Type definitions *************************************************/ #include "dictionary.h" #include "io.h" namespace commands { using namespace dictionary; using namespace io; }; namespace commands { struct CommandData { String name; String tag; void (*action)(); void (*help)(); bool autorepeat; /* Constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(CommandData));} CommandData(const char* const& str, const char* const& t, void (*a)(), void (*h)(), bool rep); ~CommandData(); }; class CommandTree:public Dictionary { private: String d_prompt; CommandTree* d_help; void (*d_entry)(); void (*d_error)(char* str); void (*d_exit)(); public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(CommandTree));} CommandTree(const char *str, void (*action)(), void (*entry)() = &relax_f, void (*error)(char*) = &default_error, void (*exit)() = &relax_f, void (*h)() = 0); ~CommandTree(); /* modifiers */ void add(const char* name, const char* tag, void (*action)(), void (*help)() = default_help, bool rep = true); void setAction(const char* str, void (*a)()); void setRepeat(const char* str, bool b); void setEntry(void (*a)()); /* inlined */ /* accessors */ void prompt() const; void entry() const; /* inlined */ void error(char *str) const; /* inlined */ void exit() const; /* inlined */ CommandTree* helpMode() const; /* inlined */ }; }; /******** Inline definitions *********************************************/ namespace commands { inline void CommandTree::setEntry(void (*a)()) {d_entry = a;} inline void CommandTree::entry() const {return d_entry();} inline void CommandTree::error(char *str) const {return d_error(str);} inline void CommandTree::exit() const {return d_exit();} inline CommandTree* CommandTree::helpMode() const {return d_help;} }; #endif positivity_final/constants.cpp0000600000175000017500000000340210011171251020336 0ustar duclouxducloux00000000000000/* This is constants.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "constants.h" namespace constants { Ulong *lmask; Ulong *leqmask; unsigned *firstbit; unsigned *lastbit; }; /**************************************************************************** This module provides some basic constants that will be used elsewhere in the program. The idea is that the call to initConstants() should be the very first one in the program; therefore this module should not depend on anything else. ****************************************************************************/ namespace constants { void initConstants() { static Ulong d_lmask[BITS(Ulong)]; static Ulong d_leqmask[BITS(Ulong)]; lmask = d_lmask; leqmask = d_leqmask; leqmask[0] = 1L; lmask[0] = 1L; for (Ulong j = 1; j < BITS(Ulong); j++) { lmask[j] = lmask[j-1] << 1; leqmask[j] = leqmask[j-1] + lmask[j]; } static unsigned d_firstbit[1<>1]+1; return; } unsigned firstBit(Ulong f) /* Returns the bit position of the first set bit in f. */ { if (f == 0) return BITS(Ulong); if (f&CHARFLAGS) return firstbit[f&CHARFLAGS]; else return firstBit(f>>CHAR_BIT)+CHAR_BIT; } unsigned lastBit(Ulong f) /* Returns the bit position of the last set bit in f. */ { if (f >> CHAR_BIT) return lastBit(f>>CHAR_BIT)+CHAR_BIT; else return lastbit[f]; } }; positivity_final/constants.h0000600000175000017500000000123110011171251020001 0ustar duclouxducloux00000000000000/* This is constants.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef CONSTANTS_H /* guard against multiple inclusions */ #define CONSTANTS_H #include "globals.h" #include namespace constants { using namespace globals; }; #define BITS(x) (CHAR_BIT*sizeof(x)) /* size of x in bits */ namespace constants { const Ulong CHARFLAGS = ~(Ulong)0 >> CHAR_BIT*(sizeof(Ulong)-1); extern Ulong *lmask; extern Ulong *leqmask; extern unsigned *firstbit; extern unsigned *lastbit; unsigned firstBit(Ulong f); void initConstants(); unsigned lastBit(Ulong f); }; #endif positivity_final/coxgroup.cpp0000600000175000017500000005374510011171251020207 0ustar duclouxducloux00000000000000/* This is coxgroup.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "coxgroup.h" #include "error.h" /************************************************************************* Chapter I -- The CoxGroup class. a description of the class should go here ... This section defines the functions not already inlined or abstract : - CoxGroup(x,l) : constructs a CoxGroup of type x and rank l; - ~CoxGroup() : destructor; accessors : - coatoms(c,g) : puts the coatoms of g in c; - isDescent(g,s) : tells if s is a descent of g; - isDihedral(g) : tells if g is a dihedral element in the group; - modify(P,tok) : accessory to parse; - parse(P) : the parsing function (should perhaps become virtual); - parseBeginGroup(P) : parses the begin-group token in an expression; - parseEndGroup(P) : parses the end-group token in an expression; - parseGroupElement(P) : parses a group element; - parseModifier(P) : parses a modifier; - prod(x,s) : increments x by s; - prod(g,x) : increments g by x; - prod(x,g) : increments x by g; manipulators : - activateKL() : activates the k-l context; - activateIKL() : activates the inverse k-l context; - activateUEKL() : activates the unequal-parameter k-l context; - cBasis(h,y) : returns in h the data for the basis element c_y; - extendContext(g) : extends the active contexts to accomodate g; - fillKL() : fills the full k-l table; - fillMu() : fills the full mu-table; - klPol(x,y) : returns the ordinary k-l polynomial P_{x,y}; - klRow(h,y) : returns the data for row y in kl-table; - mu(x,y) : returns the ordinary mu-coefficient mu(x,y); - permute(a) : permutes the context according to a; - setOutputStyle(C) : sets the output style; - sortContext() : sorts the context; - uneqcBasis(h,y) : returns in h the data for the unequal-parameter basis element c_y; *************************************************************************/ namespace coxgroup { class CoxGroup::CoxHelper { private: CoxGroup* d_W; public: void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(CoxHelper));} CoxHelper(CoxGroup* W); ~CoxHelper (); void sortContext(); void checkInverses(); }; }; namespace coxgroup { CoxGroup::CoxGroup(const Type& x, const Rank& l) /* Constructor for the abstract CoxGroup class. Does the basic initializations in the following order (the order is important) : - the Coxeter graph, which is where the Coxeter matrix gets constructed; - the interface; - the minroot table; - the kazhdan-lusztig context; */ { d_graph = new CoxGraph(x,l); if (ERRNO) /* problem with the Coxeter matrix */ return; d_mintable = new MinTable(graph()); SchubertContext* p = new StandardSchubertContext(graph()); d_klsupport = new KLSupport(p); d_interface = new Interface(x,l); d_outputTraits = new OutputTraits(graph(),interface(),Pretty()); d_help = new CoxHelper(this); return; } CoxGroup::~CoxGroup() /* Has to deconstruct what the CoxGroup constructed, in the inverse order. */ { delete d_help; delete d_kl; delete d_klsupport; delete d_mintable; delete d_graph; return; } /******** accessors **********************************************************/ void CoxGroup::coatoms(List& c, const CoxWord& g) const /* This is a simple-minded "local" function that puts a list of reduced expressions for the coatoms of g in c. */ { c.setSize(0); for (Ulong j = 0; j < g.length(); ++j) { CoxWord h(0); Ulong i = 0; for (; i < j; ++i) h.append(g[i]); ++i; for (; i < g.length(); ++i) { Generator s = g[i]-1; int d = prod(h,s); if (d == -1) goto next; } // if we get here, h is a coatom c.append(h); next: continue; } return; } bool CoxGroup::isDescent(const CoxWord& g, const Generator& s) const /* Tells if s is a descent of g. */ { LFlags f = descent(g); if (f & lmask[s]) return true; else return false; } bool CoxGroup::isDihedral(const CoxWord& g) const /* Tells if g is a dihedral element. */ { if (g.length() < 3) return true; CoxLetter s = g[0]; CoxLetter t = g[1]; for (Ulong j = 2; j < g.length(); ++j) { if (j%2) { // g[j] should be t if (g[j] != t) return false; } else { // g[j] should be s if (g[j] != s) return false; } } return true; } void CoxGroup::modify(ParseInterface& P, const Token& tok) const /* Executes the modification indicated by tok, which is assumed to be of type modifier_type. It is possible that further characters may have to be read from str. In the case of a general coxeter group, only two modifies are allowed : ! and ^ */ { if (isInverse(tok)) { inverse(P.c); } if (isPower(tok)) { Ulong m = readCoxNbr(P,ULONG_MAX); CoxGroup::power(P.c,m); } } void CoxGroup::parse(ParseInterface& P) const /* This function parses a group element from the line, starting at position r, and increments the CoxWord g with it. We have tried to include a number of convenient features, without overdoing it. The parser reads tokens from the string, skipping over any leading blank space at the beginning of each read (this means that tokens are not allowed to have leading blank spaces.) It always reads off the longest meaningful token. The following tokens are accepted : - a CoxWord prefix (postfix,separator); - a generator symbol; - a * (finite groups only) : represents the longest element; - a # : indicates that a number is to be read off; - a % : also indicates a number; - a ^ : indicates exponentiation; - a ! : indicates inversion; - a begin (end) group token; The symbols for prefix, postfix, separator, generators and grouping are provided by the interface, and already entered in the symbolTree. The grammar of expressions is as follows : expression -> expression elmt_expr elmt_expr -> (expression)[modifier] | group_elt[modifier] modifier -> empty | modifier ! | modifier * | modifier exp exp -> ^number group_elt -> coxword | #number | %number To parse an expression from a string, we try to parse a group element, followed by a modifier (= string of modifier symbols), and iterate this until we come up with an empty parse. Then we try to parse a begin-group token; if successful, we parse an expression, an end-group token, and a modifier. The parsing is managed by a stack of CoxWords; the topmost element serves to parse the current elementary expression, the next-to-topmost as an accumulator to hold the current string of elementary expressions. The return value is the number of characters read from the string. */ { for (;;) { if (parseGroupElement(P)) { if (ERRNO) return; continue; } if (parseBeginGroup(P)) { /* enter new nesting level */ continue; } if (parseEndGroup(P)) { /* exit current nesting level */ continue; } /* if we get to this point there is nothing more we can parse off */ break; } if (P.nestlevel) { /* nesting error */ ERRNO = PARSE_ERROR; return; } /* flush the current group element */ prod(P.a[0],P.c); P.c.reset(); return; } bool CoxGroup::parseBeginGroup(ParseInterface& P) const /* Tries to parse a begingroup token off P; in case of success, advances P.offset and changes the nesting level. This means simply that we increase the nestlevel, and reset it. */ { Token tok = 0; const Interface& I = interface(); Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isBeginGroup(tok)) return false; P.nestlevel++; P.a.setSize(P.nestlevel+1); P.a[P.nestlevel].reset(); P.offset += p; return true; } bool CoxGroup::parseContextNumber(ParseInterface& P) const /* Tries to parse a ContextNumber from P. This is a '%' character, followed by an integer which has to lie in the range [0,N[, where N is the current size of the enumerated part of the group. */ { const Interface& I = interface(); Token tok = 0; Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isContextNbr(tok)) return false; // if we get to this point, we must read a valid integer P.offset += p; CoxNbr x = interface::readCoxNbr(P,contextSize()); if (x == undef_coxnbr) { //error P.offset -= p; Error(CONTEXTNBR_OVERFLOW,contextSize()); ERRNO = PARSE_ERROR; } else // x is valid prod(P.c,x); return true; } bool CoxGroup::parseEndGroup(ParseInterface& P) const /* Tries to parse an endgroup token; in case of success, reduces the nestlevel after doing the necessary bookkeeping. */ { Token tok = 0; const Interface& I = interface(); Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isEndGroup(tok)) return false; if (P.nestlevel == 0) { /* error */ ERRNO = PARSE_ERROR; return true; } // make the completed group the current group element P.c = P.a[P.nestlevel]; P.nestlevel--; P.offset += p; // look for modifiers while (parseModifier(P)) { if (ERRNO) return true; } // flush modified group into accumulator prod(P.a[P.nestlevel],P.c); P.c.reset(); return true; } bool CoxGroup::parseGroupElement(ParseInterface& P) const /* This function parses a group element from the string. A group element is one of (a) a coxword (b) a context number followed by a (possibly empty) string of modifiers. The modifiers are all treated as unary postfix operators (so that, for instance, g!^2* means (((g)!)^2)*). */ { Ulong r = P.offset; if (parseContextNumber(P)) { // the next token is a ContextNumber if (ERRNO) // parse error return true; else goto modify; } // if we get to this point, we have to read a CoxWord { interface().parseCoxWord(P,mintable()); if (ERRNO) { // no CoxWord could be parsed if (P.offset == r) { // nothing was parsed ERRNO = 0; return false; } else // parse error return true; } } modify: // if we get to this point, a group element was successfully read while (parseModifier(P)) { if (ERRNO) return true; } // flush the current group element prod(P.a[P.nestlevel],P.c); P.c.reset(); if (P.offset == r) // nothing was read; c is unchanged return false; else return true; } bool CoxGroup::parseModifier(ParseInterface& P) const /* This function parses a modifier from P.str at P.offset, and acts upon it accordingly : in case of success, it applies the modifier to P.c, and advances the offset. This is the default implementation, which doesn't allow the * modifier; this is accepted only for finite groups. */ { Token tok = 0; const Interface& I = interface(); Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isModifier(tok)) return false; if (isLongest(tok)) { /* error */ ERRNO = PARSE_ERROR; return true; } P.offset += p; modify(P,tok); return true; } int CoxGroup::prod(CoxNbr& x, const Generator& s) const /* This function increments x by right multiplication with s (i.e., it could have been written as x *= s). Returns +1 if the length goes up, -1 if the length goes down. Values of rank <= s < 2*rank correspond to right products. */ { CoxNbr x_old = x; x = schubert().shift(x,s); if (x > x_old) return 1; else return -1; } int CoxGroup::prod(CoxNbr& x, const CoxWord& g) const /* Multiplies x consecutively by the terms in g. Stops at the first undefined operation. Returns the length increase. */ { int l = 0; for (Ulong j = 0; j < g.length(); ++j) { l += prod(x,g[j]-1); if (x == undef_coxnbr) break; } return l; } int CoxGroup::prod(CoxWord& g, const CoxNbr& d_x) const /* Multiplies g by the terms in x. Returns the length increase. */ { int l = 0; CoxNbr x = d_x; while(x) { Generator s = firstBit(ldescent(x)); l += prod(g,s); prod(x,s+rank()); } return l; } /******** manipulators ******************************************************/ void CoxGroup::activateKL() /* This function activates the ordinary k-l context if it isn't already active. A memory error could happen in the process, but is not caught (i.e. CATCH_MEMORY_ERROR is not set); the program will simply exit printing the memory status. */ { if (d_kl == 0) { d_kl = new kl::KLContext(d_klsupport); } return; } void CoxGroup::activateIKL() /* This function activates the inverse k-l context if it isn't already active. */ { if (d_invkl == 0) { d_invkl = new invkl::KLContext(d_klsupport); } return; } void CoxGroup::activateUEKL() /* This function activates the unequal-parameter k-l context if it isn't already active. Forwards the error ABORT in case of failure (this means that there was a problem while getting the lengths from the user.) */ { if (d_uneqkl == 0) { d_uneqkl = new uneqkl::KLContext(d_klsupport,graph(),interface()); if (ERRNO) { Error(ERRNO); delete d_uneqkl; d_uneqkl = 0; } } return; } void CoxGroup::cBasis(kl::HeckeElt& h, const CoxNbr& y) /* Puts in h the data of the full row for y in the k-l context corresponding to y, sorted in the order of the current normal forms. Activates the context if necessary. */ { activateKL(); kl::cBasis(h,y,*d_kl); return; } CoxNbr CoxGroup::extendContext(const CoxWord& g) /* This function extends the active contexts to acccomodate g. An active context is one that has a non-zero pointer. Currently there are three k-l contexts : ordinary, unequal parameter, and inverse. Parabolic stuff should be numbered independently. This is the place where we try to cope gently with a memory extension error; we wish to leave things as they were if the extension fails. Forwards the error ERROR_WARNING in case of failure. */ { Ulong prev_size = contextSize(); CoxNbr x = d_klsupport->extendContext(g); if (ERRNO) { goto revert; } if (d_kl) { d_kl->setSize(contextSize()); if (ERRNO) goto revert; } if (d_uneqkl) { d_uneqkl->setSize(contextSize()); if (ERRNO) goto revert; } if (d_invkl) { d_invkl->setSize(contextSize()); if (ERRNO) goto revert; } return x; revert: d_klsupport->revertSize(prev_size); if (d_kl) d_kl->revertSize(prev_size); if (d_uneqkl) d_uneqkl->revertSize(prev_size); if (d_invkl) d_invkl->revertSize(prev_size); ERRNO = ERROR_WARNING; return undef_coxnbr; } void CoxGroup::fillIKL() /* This function fills the whole k-l table up to the size of the current schubert context, for inverse kazhdan-lusztig polynomials, avtrer having activated the context if necessary. */ { activateIKL(); d_invkl->fillKL(); return; } void CoxGroup::fillIMu() /* This function fills the whole mu-table up to the size of the current schubert context, for the inverse kazhdan-lusztig polynomials, after having activated the context if necessary. */ { activateIKL(); d_invkl->fillMu(); return; } void CoxGroup::fillKL() /* This function fills the whole k-l table up to the size of the current schubert context, after having activated the context if necessary. */ { activateKL(); d_kl->fillKL(); return; } void CoxGroup::fillMu() /* This function fills the whole mu-table up to the size of the current schubert context, after having activated the context if necessary. */ { activateKL(); d_kl->fillMu(); return; } void CoxGroup::fillUEKL() /* This function fills the whole unequal-parameter k-l table up to the size of the current schubert context, after having activated the context if necessary. */ { activateUEKL(); d_uneqkl->fillKL(); return; } void CoxGroup::fillUEMu() /* This function fills the whole unequal-parameter mu-tables up to the size of the current schubert context, after having activated the context if necessary. */ { activateUEKL(); d_uneqkl->fillMu(); return; } const invkl::KLPol& CoxGroup::invklPol(const CoxNbr& x, const CoxNbr& y) /* Returns the inverse k-l polynomial Q_{x,y}, after activating the context if necessary. */ { activateIKL(); return d_invkl->klPol(x,y); } void CoxGroup::invklRow(invkl::HeckeElt& h, const CoxNbr& y) /* Puts in h the data of the full row for y in the inverse k-l context corresponding to y, sorted in the order of the current normal forms. Activates the context if necessary. */ { activateIKL(); d_invkl->row(h,y); return; } const kl::KLPol& CoxGroup::klPol(const CoxNbr& x, const CoxNbr& y) /* Returns the ordinary k-l polynomial P_{x,y}, after activating the context if necessary. */ { activateKL(); return d_kl->klPol(x,y); } void CoxGroup::klRow(kl::HeckeElt& h, const CoxNbr& y) /* Puts in h the data of the full row for y in the k-l context corresponding to y, sorted in the order of the current normal forms. Activates the context if necessary. */ { activateKL(); d_kl->row(h,y); return; } KLCoeff CoxGroup::mu(const CoxNbr& x, const CoxNbr& y) /* Returns the ordinary mu-coefficent mu(x,y), after activating the context if necessary. */ { activateKL(); return d_kl->mu(x,y); } void CoxGroup::permute(const Permutation& a) /* This function permutes all the active contexts w.r.t. the permutation a. The idea is that we _renumber_ the context; a is the permutation of the range [0,size[ which gives for each number x the new number of the same group element. So in terms of group elements the correspondence is that new[a(x)] = old[x]. Applying the permutation to group-valued functions is trivial : just permute the values using a. Applying it to functions with range in the group, we need to compose on the right with the inverse permutation : new_f(x) = old_f(a^{-1}(x)). For functions from group to group, we need to do both. What we have to do here is : - permute the schubert context itself; - permute inverse; - permute last; - permute involution; - permute the extrList; - permute the various kl-contexts; Note that extrList should be seen as a table of enumerated subsets of the group. The various kllists are tables of sequences of polynomials, enumerated in accordance with the extrList. The mulists are also tables of enumerated subsets of the group, together with additional data. A further requirement is that these enumerations be increasing; so we will furthermore have to sort each extrrow, and the rows that should be compatible with it, and each mu-row. Finally, we have imposed on ourselves the burden of writing only one of the pairs (y,y_inverse), viz. the one with the smaller index. So we need to maintain that requirement as well. */ { d_klsupport->permute(a); if (d_kl) d_kl->permute(a); if (d_invkl) d_invkl->permute(a); if (d_uneqkl) d_uneqkl->permute(a); d_help->checkInverses(); d_help->sortContext(); return; } void CoxGroup::uneqcBasis(uneqkl::HeckeElt& h, const CoxNbr& y) /* Puts in h the data of the full row for y in the k-l context corresponding to y, sorted in the order of the current normal forms. Activates the context if necessary. */ { activateUEKL(); uneqkl::cBasis(h,y,*d_uneqkl); return; } const uneqkl::KLPol& CoxGroup::uneqklPol(const CoxNbr& x, const CoxNbr& y) /* Returns the unequal-parameter k-l polynomial P_{x,y}, after activating the context if necessary. */ { activateUEKL(); return d_uneqkl->klPol(x,y); } const uneqkl::MuPol& CoxGroup::uneqmu(const Generator& s, const CoxNbr& x, const CoxNbr& y) /* Returns the unequal-parameter mu-polynomial mu_{s,x,y}, after activating the context if necessary. */ { activateUEKL(); return d_uneqkl->mu(s,x,y); } void CoxGroup::uneqklRow(uneqkl::HeckeElt& h, const CoxNbr& y) /* Puts in e_row and kl_row the data of the full row of the unequal-parameter k-l context corresponding to y, sorted in the short-lex order of the current normal forms. Activates the context if necessary. */ { activateUEKL(); d_uneqkl->row(h,y); return; } }; /***************************************************************************** Chapter II -- The CoxHelper class. This class provides some private helper functions for managing a CoxGroup structure, that we don't want in the coxgroup.h file. The following functions are provided : - CoxHelper(W); _ ~CoxHelper(); *****************************************************************************/ namespace coxgroup { CoxGroup::CoxHelper::CoxHelper(CoxGroup* W):d_W(W) {} CoxGroup::CoxHelper::~CoxHelper() {} void CoxGroup::CoxHelper::sortContext() /* This function is an auxiliary to permute; it takes care of putting things in increasin context number order after the permutation. */ { KLSupport* kls = d_W->d_klsupport; for (CoxNbr y = 0; y < d_W->contextSize(); ++y) { if (!kls->isExtrAllocated(y)) continue; Permutation a(0); sortI(d_W->extrList(y),a); kls->applyIPermutation(y,a); /* apply to the various klcontexts */ if (d_W->d_kl) { d_W->d_kl->applyIPermutation(y,a); } if (d_W->d_invkl) { d_W->d_invkl->applyIPermutation(y,a); } if (d_W->d_uneqkl) { d_W->d_uneqkl->applyIPermutation(y,a); } } return; } void CoxGroup::CoxHelper::checkInverses() /* This function is an auxiliary to permute; it takes care of checking that the smaller one of the pairs (y,y_inverse) is allocated in the extrList and in all lists which depend on that. */ { KLSupport& kls = *(d_W->d_klsupport); for (CoxNbr y = 0; y < d_W->contextSize(); ++y) { CoxNbr yi = d_W->inverse(y); if (yi <= y) continue; if (kls.isExtrAllocated(y)) continue; /* if we get here, we should transfer lists from yi to y */ kls.applyInverse(y); if (d_W->d_kl) d_W->d_kl->applyInverse(y); if (d_W->d_invkl) d_W->d_invkl->applyInverse(y); if (d_W->d_uneqkl) d_W->d_uneqkl->applyInverse(y); } return; } }; positivity_final/coxgroup.h0000600000175000017500000004036510115107371017655 0ustar duclouxducloux00000000000000/* This is coxgroup.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /************************************************************************** This file presents the main type in this program, viz. the CoxGroup class. This is the base class for the hierarchy of coxeter group classes, ranging from the most general ones considered in this program (rank <= 255, coefficients of Coxeter matris <= COXENTRY_MAX) to the most special, the class SmallCoxGroup. We have adhered to the philosophy that all non-leaf classes in the hierarchy should be abstract. So this file contains only the root of the hierarchy, as an abstract class. The layout of the Coxeter hierarchy as considered in this program is as follows : CoxGroup(a) FiniteCoxGroup(a) FiniteBigRankCoxGroup(a) GeneralFBRCoxGroup(c) FiniteMedRankCoxGroup(a) GeneralFMRCoxGroup(c) FiniteSmallRankCoxGroup(a) GeneralFSRCoxGroup(c) SmallCoxGroup(a) GeneralSCoxGroup(c) TypeACoxGroup(a) TypeABigRankCoxGroup(c) TypeAMedRankCoxGroup(c) TypeASmallRankCoxGroup(c) TypeASmallCoxGroup(c) AffineCoxGroup(a) AffineBigRankCoxGroup(a) GeneralABRCoxGroup(c) AffineMedRankCoxGroup(a) GeneralAMRCoxGroup(c) AffineSmallRankCoxGroup(a) GeneralASRCoxGroup(c) GeneralCoxGroup(a) BigRankCoxGroup(a) GeneralBRCoxGroup(c) MedRankCoxGroup(a) GeneralMRCoxGroup(c) SmallRankCoxGroup(a) GeneralSRCoxGroup(c) **************************************************************************/ #ifndef COXGROUP_H /* guarantee single inclusion */ #define COXGROUP_H #include "globals.h" namespace coxgroup { using namespace globals; }; /******** type definitions **************************************************/ #include "coxtypes.h" #include "files.h" #include "graph.h" #include "hecke.h" #include "interface.h" #include "invkl.h" #include "kl.h" #include "klsupport.h" #include "minroots.h" #include "transducer.h" #include "uneqkl.h" namespace coxgroup { using namespace coxtypes; using namespace files; using namespace graph; using namespace hecke; using namespace interface; using namespace klsupport; using namespace minroots; using namespace transducer; }; class coxgroup::CoxGroup { // has been declared in coxtypes.h protected: CoxGraph* d_graph; MinTable* d_mintable; KLSupport* d_klsupport; kl::KLContext* d_kl; invkl::KLContext* d_invkl; uneqkl::KLContext* d_uneqkl; Interface* d_interface; OutputTraits* d_outputTraits; struct CoxHelper; /* provides helper functions */ CoxHelper* d_help; friend struct CoxHelper; public: void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(CoxGroup));} /******** Chapter 0 : CoxGroup objects *************************************/ CoxGroup(const Type& x, const Rank& l); virtual ~CoxGroup(); CoxGraph& graph(); /* inlined */ virtual Interface& interface(); /* inlined */ MinTable& mintable(); /* inlined */ KLSupport& klsupport(); /* inlined */ kl::KLContext& kl(); /* inlined */ invkl::KLContext& invkl(); /* inlined */ uneqkl::KLContext& uneqkl(); /* inlined */ virtual OutputTraits& outputTraits(); /* inlined */ const CoxGraph& graph() const; /* inlined */ virtual const Interface& interface() const; /* inlined */ const MinTable& mintable() const; /* inlined */ const KLSupport& klsupport() const; /* inlined */ const kl::KLContext& kl() const; /* inlined */ const uneqkl::KLContext& uneqkl() const; /* inlined */ const SchubertContext& schubert() const; /* inlined */ virtual const OutputTraits& outputTraits() const; /* inlined */ void activateKL(); void activateIKL(); void activateUEKL(); /* graph data */ CoxEntry M(Generator s, Generator t) const; /* inlined */ Rank rank() const; /* inlined */ const Type& type() const; /* inlined */ virtual CoxSize order() const = 0; virtual bool isFullContext() const; /* inlined */ /******** Chapter I : Elementary operations ********************************/ /* word operations */ virtual int insert(CoxWord& g, const Generator& s) const; /* inlined */ virtual const CoxWord& inverse(CoxWord& g) const; /* inlined */ virtual const CoxWord& normalForm(CoxWord& g) const; /* inlined */ virtual const CoxWord& power(CoxWord& g, const Ulong& m) const; /* inlined */ virtual int prod(CoxWord& g, const Generator& s) const; /* inlined */ virtual int prod(CoxWord& g, const CoxWord& h) const; /* inlined */ virtual const CoxWord& reduced(CoxWord& g, CoxWord& h) const; /* inlined */ /* descent sets */ virtual LFlags descent(const CoxWord& g) const; /* inlined */ virtual LFlags ldescent(const CoxWord& g) const; /* inlined */ virtual LFlags rdescent(const CoxWord& g) const; /* inlined */ bool isDescent(const CoxWord& g, const Generator& s) const; /******** Chapter II : Schubert context **************************************/ virtual CoxNbr contextNumber(const CoxWord& g) const; /* inlined */ CoxNbr contextSize() const; /* inlined */ Length length(const CoxNbr& x) const; /* inlined */ virtual CoxNbr extendContext(const CoxWord& g); virtual void permute(const Permutation& a); virtual LFlags descent(const CoxNbr& x) const; /* inlined */ virtual LFlags ldescent(const CoxNbr& x) const; /* inlined */ virtual LFlags rdescent(const CoxNbr& x) const; /* inlined */ virtual CoxNbr inverse(const CoxNbr& x) const; /* inlined */ virtual int prod(CoxNbr& x, const Generator& s) const; virtual int lprod(CoxNbr& x, const Generator& s) const; /* inlined */ virtual int prod(CoxWord& g, const CoxNbr& x) const; virtual int prod(CoxNbr& x, const CoxWord& g) const; virtual const List& extrList(const CoxNbr& x) const; /* inlined */ /******** Chapter III : Bruhat ordering **************************************/ virtual void coatoms(List& c, const CoxWord& g) const; virtual const CoatomList& coatoms(const CoxNbr& x) const ; /* inlined */ virtual void extractClosure(BitMap& b, const CoxNbr& x) const; /* inlined */ virtual bool inOrder(const CoxWord& h, const CoxWord& g) const; /* inlined */ virtual bool inOrder(List& a, const CoxWord& h, const CoxWord& g) const; /* inlined */ virtual bool inOrder(const CoxNbr& x, const CoxNbr& y) const; /* inlined */ virtual bool isDihedral(const CoxWord& g) const; /******** Chapter IV : Kazhdan-Lusztig functions *****************************/ virtual void cBasis(kl::HeckeElt& h, const CoxNbr& y); virtual void fillKL(); virtual void fillMu(); virtual const kl::KLPol& klPol(const CoxNbr& x, const CoxNbr& y); virtual void klRow(kl::HeckeElt& h, const CoxNbr& y); virtual KLCoeff mu(const CoxNbr& x, const CoxNbr& y); virtual void fillIKL(); virtual void fillIMu(); virtual const invkl::KLPol& invklPol(const CoxNbr& x, const CoxNbr& y); virtual void invklRow(invkl::HeckeElt& h, const CoxNbr& y); virtual void fillUEKL(); virtual void fillUEMu(); virtual const uneqkl::KLPol& uneqklPol(const CoxNbr& x, const CoxNbr& y); virtual const uneqkl::MuPol& uneqmu(const Generator& s, const CoxNbr& x, const CoxNbr& y); virtual void uneqcBasis(uneqkl::HeckeElt& h, const CoxNbr& y); virtual void uneqklRow(uneqkl::HeckeElt& h, const CoxNbr& y); /******** Chapter V : I/O ***************************************************/ /* elementary i/o functions */ const Permutation& ordering() const; /* inlined */ String& append(String& str, const Generator& s) const; /* inlined */ String& append(String& str, const CoxWord& g) const; /* inlined */ String& append(String& str, const LFlags& f) const; /* inlined */ void printSymbol(FILE* file, const Generator& s) const; /* inlined */ void print(FILE* file, const CoxWord& g) const; /* inlined */ void print(FILE* file, const CoxNbr& x) const; /* inlined */ void printFlags(FILE* file, const LFlags& f) const; /* inlined */ void parse(ParseInterface& P) const; virtual bool parseGroupElement(ParseInterface& P) const; bool parseBeginGroup(ParseInterface& P) const; bool parseContextNumber(ParseInterface& P) const; bool parseEndGroup(ParseInterface& P) const; virtual bool parseModifier(ParseInterface& P) const; virtual void modify(ParseInterface& P, const Token& tok) const; /* modifying the interface */ template void setOutputTraits(C); void setInPostfix(const String& a); /* inlined */ void setInPrefix(const String& a); /* inlined */ void setInSeparator(const String& a); /* inlined */ void setInSymbol(const Generator& s, const String& a); /* inlined */ void setOrdering(const Permutation& order); /* inlined */ void setOutPostfix(const String& a); /* inlined */ void setOutPrefix(const String& a); /* inlined */ void setOutSeparator(const String& a); /* inlined */ void setOutSymbol(const Generator& s, const String& a); /* inlined */ template void printHeckeElt(FILE* file, const H& h); /* inlined */ }; /******** Inline implementations ******************************************/ namespace coxgroup { /* Chapter 0 */ inline CoxGraph& CoxGroup::graph() {return *d_graph;} inline MinTable& CoxGroup::mintable() {return *d_mintable;} inline KLSupport& CoxGroup::klsupport() {return *d_klsupport;} inline kl::KLContext& CoxGroup::kl() {activateKL(); return *d_kl;} inline invkl::KLContext& CoxGroup::invkl() {activateIKL(); return *d_invkl;} inline uneqkl::KLContext& CoxGroup::uneqkl() {activateUEKL(); return *d_uneqkl;} inline Interface& CoxGroup::interface() {return *d_interface;} inline OutputTraits& CoxGroup::outputTraits() {return *d_outputTraits;} inline const CoxGraph& CoxGroup::graph() const {return *d_graph;} inline const MinTable& CoxGroup::mintable() const {return *d_mintable;} inline const KLSupport& CoxGroup::klsupport() const {return *d_klsupport;} inline const kl::KLContext& CoxGroup::kl() const {return *d_kl;} inline const uneqkl::KLContext& CoxGroup::uneqkl() const {return *d_uneqkl;} inline const SchubertContext& CoxGroup::schubert() const {return d_klsupport->schubert();} inline const Interface& CoxGroup::interface() const {return *d_interface;} inline const OutputTraits& CoxGroup::outputTraits() const {return *d_outputTraits;} inline CoxEntry CoxGroup::M(Generator s, Generator t) const {return(graph().M(s,t));} inline Rank CoxGroup::rank() const {return(graph().rank());} inline const Type& CoxGroup::type() const {return graph().type();} inline bool CoxGroup::isFullContext() const {return false;} /* Chapter I */ inline int CoxGroup::insert(CoxWord& g, const Generator& s) const {return mintable().insert(g,s,ordering());} inline const CoxWord& CoxGroup::inverse(CoxWord& g) const {return mintable().inverse(g);} inline const CoxWord& CoxGroup::normalForm(CoxWord& g) const {return mintable().normalForm(g,interface().order());} inline const CoxWord& CoxGroup::power(CoxWord& g, const Ulong& m) const {return mintable().power(g,m);} inline int CoxGroup::prod(CoxWord& g, const Generator& s) const {return mintable().prod(g,s);} inline int CoxGroup::prod(CoxWord& g, const CoxWord& h) const {return mintable().prod(g,h);} inline const CoxWord& CoxGroup::reduced(CoxWord& g, CoxWord& h) const {return mintable().reduced(g,h);} inline LFlags CoxGroup::descent(const CoxWord& g) const {return mintable().descent(g);} inline LFlags CoxGroup::ldescent(const CoxWord& g) const {return mintable().ldescent(g);} inline LFlags CoxGroup::rdescent(const CoxWord& g) const {return mintable().rdescent(g);} /* Chapter II */ inline CoxNbr CoxGroup::contextNumber(const CoxWord& g) const {return schubert().contextNumber(g);} inline CoxNbr CoxGroup::contextSize() const {return d_klsupport->size();} inline Length CoxGroup::length(const CoxNbr& x) const {return d_klsupport->length(x);} inline LFlags CoxGroup::descent(const CoxNbr& x) const {return schubert().descent(x);} inline LFlags CoxGroup::ldescent(const CoxNbr& x) const {return schubert().ldescent(x);} inline LFlags CoxGroup::rdescent(const CoxNbr& x) const {return schubert().rdescent(x);} inline CoxNbr CoxGroup::inverse(const CoxNbr& x) const {return d_klsupport->inverse(x);} inline int CoxGroup::lprod(CoxNbr& x, const Generator& s) const {return prod(x,s+rank());} inline const List& CoxGroup::extrList(const CoxNbr& x) const {return d_klsupport->extrList(x);} /* Chapter III */ inline const CoatomList& CoxGroup::coatoms(const CoxNbr& x) const {return schubert().hasse(x);} inline void CoxGroup::extractClosure(BitMap& b, const CoxNbr& x) const {return schubert().extractClosure(b,x);} inline bool CoxGroup::inOrder(const CoxWord& g, const CoxWord& h) const {return mintable().inOrder(g,h);} inline bool CoxGroup::inOrder(List& a, const CoxWord& g, const CoxWord& h) const {return mintable().inOrder(a,g,h);} inline bool CoxGroup::inOrder(const CoxNbr& x, const CoxNbr& y) const {return schubert().inOrder(x,y);} /* Chapter V */ inline const Permutation& CoxGroup::ordering() const {return interface().order();} inline String& CoxGroup::append(String& str, const Generator& s) const {return appendSymbol(str,s,interface());} inline String& CoxGroup::append(String& str, const CoxWord& g) const {return interface::append(str,g,interface());} inline String& CoxGroup::append(String& str, const LFlags& f) const {return interface::append(str,f,interface());} inline void CoxGroup::printSymbol(FILE* file, const Generator& s) const {return interface::printSymbol(file,s,interface());} inline void CoxGroup::print(FILE* file, const CoxWord& g) const {return interface().print(file,g);} inline void CoxGroup::print(FILE* file, const CoxNbr& x) const {return schubert().print(file,x,interface());} inline void CoxGroup::printFlags(FILE* file, const LFlags& f) const {return interface::print(file,f,interface());} inline void CoxGroup::setInPostfix(const String& a) {interface().setInPostfix(a);} inline void CoxGroup::setInPrefix(const String& a) {interface().setInPrefix(a);} inline void CoxGroup::setInSeparator(const String& a) {interface().setInSeparator(a);} inline void CoxGroup::setInSymbol(const Generator& s, const String& a) {interface().setInSymbol(s,a);} inline void CoxGroup::setOrdering(const Permutation& order) {interface().setOrder(order);} inline void CoxGroup::setOutPostfix(const String& a) {interface().setOutPostfix(a);} inline void CoxGroup::setOutPrefix(const String& a) {interface().setOutPrefix(a);} inline void CoxGroup::setOutSeparator(const String& a) {interface().setOutSeparator(a);} inline void CoxGroup::setOutSymbol(const Generator& s, const String& a) {interface().setOutSymbol(s,a);} template inline void CoxGroup::printHeckeElt(FILE* file, const H& h) {files::printHeckeElt(file,h,schubert(),outputTraits());} }; /******** template definitions ***********************************************/ namespace coxgroup { template void CoxGroup::setOutputTraits(C) {new(d_outputTraits) OutputTraits(graph(),interface(),C());} }; #endif positivity_final/coxtypes.cpp0000600000175000017500000001153510011171251020206 0ustar duclouxducloux00000000000000/* This is coxtypes.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "coxtypes.h" /**************************************************************************** Chapter I -- The CoxWord class. This section defines the functions in the CoxWord class that are not inlined : - the constructor CoxWord(n); - the destructor ~CoxWord(); - append(a) : appends the letter a to the end of g; - append(h) : appends the word h to the end of g; - erase(j) : erases the j-th letter from g; - insert(j,a) : inserts the letter a in the j-th place in g; - reset() : resets g to the identity element; - setSubWord(h,first,r) : sets a subword in g; ****************************************************************************/ namespace coxtypes { CoxWord::CoxWord(const Ulong& n):d_list(n+1) { d_list.setSize(1); } CoxWord::~CoxWord() {} CoxWord& CoxWord::append(const CoxLetter& a) /* Appends a to the end of g, resizing as necessary. Recall that for now our CoxWords are always zero-terminated strings! */ { d_list[d_list.size()-1] = a; d_list.append('\0'); return *this; } CoxWord& CoxWord::append(const CoxWord& h) /* Appends h to the end of g. NOTE : care should be exercised in applying this function, that l(gh) = l(g) + l(h) in W; otherwise we would violate the basic principle that only reduced words enter the program. Use prod otherwise. */ { d_list.setData(h.d_list.ptr(),d_list.size()-1,h.d_list.size()); return *this; } CoxWord& CoxWord::erase(const Length& j) /* Erases the j-th letter from g. NOTE : care should be exercised in applying this function, that the result be reduced; otherwise we would violate the basic principle that only reduced words enter the program. */ { d_list.setData(d_list.ptr()+j+1,j,d_list.size()-1-j); d_list.setSize(d_list.size()-1); return *this; } CoxWord& CoxWord::insert(const Length& j, const CoxLetter& a) /* Inserts a at the j-th place in g. NOTE : care should be exercised in applying this function, that the result be reduced; otherwise we would violate the basic principle that only reduced words enter the program. */ { d_list.setSize(d_list.size()+1); d_list.setData(d_list.ptr()+j,j+1,d_list.size()-1-j); d_list[j] = a; return *this; } CoxWord& CoxWord::reset() /* Sets g to the identity. */ { d_list.setSize(1); d_list[0] = '\0'; return *this; } CoxWord& CoxWord::setSubWord(const CoxWord& h, const Length& first, const Length& r) { d_list.setData(h.d_list.ptr(),first,r); return *this; } }; /***************************************************************************** Chapter II -- Comparison operators This section defines the comparison operators for CoxWords. We do word comparisons textually because this is so much cheaper. If comparisons as group elements are required, normalize first. - operator== (g,h) : tells if g and h are equal as words; - operator< (g,h) : tells if g h.length()) return false; for (Ulong j = 0; j < g.length(); ++j) { if (g[j] < h[j]) return true; if (g[j] > h[j]) return false; } /* if we get to this point, words are equal */ return false; } }; /**************************************************************************** Chapter III -- Input/Output. This section provides some input/output functions for the basic types defined in this module. The following functions are provided : - append(str,x) : appends a CoxNbr to the string; - print(file,a,l) : prints the array a in rank l on the file; ****************************************************************************/ namespace coxtypes { String& append(String& str, const CoxNbr& x) /* Appends x to str in numeral form; uses buf to write out the value. */ { static String buf(digits(COXNBR_MAX,10)+1); buf.setLength(sprintf(buf.ptr(),"%lu",static_cast(x))); append(str,buf); return str; } void print(FILE *outputfile, CoxArr a, Rank l) /* Prints a in array form on the outputfile.. */ { fprintf(outputfile,"["); for (Ulong j = 0; j < l; ++j) { fprintf(outputfile,"%d",a[j]); if (j+1 < l) /* there is more to come */ { fprintf(outputfile,","); } } fprintf(outputfile,"]"); return; } }; positivity_final/coxtypes.h0000600000175000017500000001136210011171251017651 0ustar duclouxducloux00000000000000/* This is coxtypes.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /**************************************************************************** This file provides the basic type definitions for the Coxeter program. ****************************************************************************/ #ifndef COXTYPES_H /* guard against multiple inclusions */ #define COXTYPES_H #include "globals.h" #include #include "io.h" namespace coxtypes { using namespace globals; using namespace io; }; /* type declarations and bounds */ namespace coxgroup { class CoxGroup; // forward declaration }; namespace coxtypes { typedef unsigned short Rank; typedef Ulong CoxSize; /* should hold at least 32 bits */ typedef Ulong BettiNbr; /* should hold at least 32 bits */ typedef unsigned CoxNbr; /* should fit into a CoxSize */ typedef CoxNbr ParSize; /* this should not be changed */ typedef unsigned short ParNbr; /* should fit into a CoxNbr */ typedef ParNbr *CoxArr; typedef unsigned char CoxLetter; /* for string representations */ typedef CoxLetter Generator; /* internal representation of generators*/ typedef unsigned short Length; typedef Ulong StarOp; /* for numbering star operations */ class CoxWord; /* constants */ // const Rank RANK_MAX = 255; /* to enable string representations */ // MEDRANK_MAX bits should fit in a LFlags const Rank MEDRANK_MAX = CHAR_BIT*sizeof(Ulong); // 2*SMALLRANK_MAX bits should fit in a LFlags const Rank SMALLRANK_MAX = CHAR_BIT*sizeof(Ulong)/2; const Rank RANK_MAX = SMALLRANK_MAX; /* temporary restriction */ const Generator GENERATOR_MAX = RANK_MAX-1; /* top value is reserved */ const Generator undef_generator = RANK_MAX; const CoxSize COXSIZE_MAX = ULONG_MAX-2; /* top values are reserved */ const CoxSize infinite_coxsize = COXSIZE_MAX+1; const CoxSize undef_coxsize = COXSIZE_MAX+2; const BettiNbr BETTI_MAX = ULONG_MAX-1; /* top value is reserved */ const BettiNbr undef_betti = BETTI_MAX+1; const CoxNbr COXNBR_MAX = UINT_MAX-1; /* top value is reserved */ const CoxNbr undef_coxnbr = COXNBR_MAX+1; const ParSize LPARNBR_MAX = COXNBR_MAX-RANK_MAX-1;/* top value is reserved */ const ParNbr PARNBR_MAX = USHRT_MAX-RANK_MAX-1; /* top value is reserved */ const Length LENGTH_MAX = USHRT_MAX-1; /* top value is reserved */ const Length undef_length = LENGTH_MAX+1; const StarOp STAR_MAX = ULONG_MAX-1; /* top value is reserved */ const StarOp undef_starop = STAR_MAX+1; }; /* functions provided by coxtypes.h */ #include "io.h" namespace coxtypes { using namespace io; }; namespace coxtypes { bool operator== (const CoxWord& g, const CoxWord& h); bool operator< (const CoxWord& g, const CoxWord& h); bool operator> (const CoxWord& g, const CoxWord& h); /* inlined */ String& append(String& str, const CoxNbr& x); void print(FILE *outputfile, CoxArr a, Rank l); }; /******** Implementation ****************************************************/ #include "list.h" namespace coxtypes { using namespace list; }; namespace coxtypes { class CoxWord { private: List d_list; public: /* constructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(CoxWord));} CoxWord():d_list(0) {}; /* empty word */ CoxWord(const Ulong& n); ~CoxWord(); /* accessors */ const CoxLetter& operator[] (const Length& j) const; /* inlined */ Length length() const; /* inlined */ /* modifiers */ CoxWord& operator= (const CoxWord& h); /* inlined */ CoxLetter& operator[] (const Length& j); /* inlined */ CoxWord& append(const CoxLetter& a); CoxWord& append(const CoxWord& h); CoxWord& erase(const Length& j); CoxWord& insert(const Length& j, const CoxLetter& a); CoxWord& reset(); void setLength(Length n); /* inlined */ CoxWord& setSubWord(const CoxWord& h, const Length& first, const Length& r); }; }; /******** Inline definitions ***********************************************/ namespace coxtypes { inline bool operator> (const CoxWord& g, const CoxWord& h) {return h < g;} /* class CoxWord */ inline const CoxLetter& CoxWord::operator[] (const Length& j) const {return d_list[j];} inline Length CoxWord::length() const {return d_list.size()-1;} inline CoxWord& CoxWord::operator=(const CoxWord & h) {d_list.assign(h.d_list); return *this;} inline CoxLetter& CoxWord::operator[] (const Length& j) {return d_list[j];} inline void CoxWord::setLength(Length n) {d_list.setSize(n+1);} }; #endif positivity_final/dictionary.h0000600000175000017500000000354710034764346020170 0ustar duclouxducloux00000000000000/* This is dictionary.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef DICTIONARY_H /* guard against multiple inclusions */ #define DICTIONARY_H #include "globals.h" namespace dictionary { using namespace globals; }; /******** type declarations *************************************************/ namespace dictionary { template class Dictionary; template struct DictCell; }; #include "memory.h" #include "io.h" namespace dictionary { using namespace memory; using namespace io; }; /******** function declarations *********************************************/ namespace dictionary { template void printExtensions(FILE* file, DictCell* cell, String& name, bool& first, const char* sep = ","); }; /* class definitions */ namespace dictionary { template struct DictCell { T *ptr; DictCell *left; DictCell *right; char letter; bool fullname; bool uniquePrefix; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(DictCell));} DictCell() {/* not implemented */}; DictCell(char c, T* v, bool f, bool u, DictCell *l = 0, DictCell *r = 0) :ptr(v), left(l), right(r), letter(c), fullname(f), uniquePrefix(u) {}; virtual ~DictCell(); /* accessors */ T* value() const {return ptr;} }; template class Dictionary { protected: DictCell* d_root; public: /* creators and destructors */ Dictionary(); ~Dictionary(); /* modifiers */ void insert(const String& str, T* const value); void remove(const String& str); /* accessors */ T* find(const String& str) const; DictCell* findCell(const String& str) const; DictCell* root() {return d_root;} }; }; #include "dictionary.hpp" #endif positivity_final/dictionary.hpp0000600000175000017500000001310110011171251020471 0ustar duclouxducloux00000000000000/* This is dictionary.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /**************************************************************************** This module contains an implementation of dictionaries. For us, a dictionary is a search structure (in practice, a tree) recognizing strings. The operations which are allowed are inserting and deleting a string, and searching for a given string. The return value is a pointer; this allows us to have a unique typesize. ****************************************************************************/ /**************************************************************************** Chapter I -- The Dictionary class. ****************************************************************************/ namespace dictionary { template Dictionary::Dictionary() /* Default constructor for the Dictionary class. A dictionary is always created with a root cell, corresponding to the empty string "". */ { d_root = new DictCell(0,0,true,false); } template Dictionary::~Dictionary() /* Destructor for the Dictionary class. The destructor has to run through the cells, and destroy each of them. */ { delete d_root; } template DictCell* Dictionary::findCell(const String& str) const /* Searches for a value in the dictionary. Returns NULL in case of failure. NOTE : in fact, recognizes if str is a *prefix* of a word in the dictionary. It is up to the client to decide what to do about incomplete words (return a special value, for instance.) It is not possible to restrict to leaves because in practice embedded dictionary words will be common. */ { DictCell *cell = d_root; for (Ulong j = 0; str[j]; ++j) { if (cell->left == 0) /* leaf reached */ return 0; cell = cell->left; char c = str[j]; while ((cell->right) && (c > cell->letter)) cell = cell->right; if (c != cell->letter) return 0; } return cell; } template T* Dictionary::find(const String& str) const { DictCell* dc = findCell(str); if (dc) return dc->value(); else return 0; } template void Dictionary::insert(const String& str, T* const value) /* Inserts a new word in the dictionary. The root of the tree always corresponds to the empty string "" (which may or may not be considered to be in the dictionary.) The nodes are classified in three types : dictionary words, unique prefixes (i.e., strings which are prefixes to a unique dictionary word) and non-unique prefixes. */ { DictCell* cell = findCell(str); if (cell && cell->fullname) { /* word was already in the dictionary */ cell->ptr = value; return; } /* from now on we are sure that the word is not already in the dictionary */ cell = d_root; for (Ulong j = 0; str[j]; ++j) { if (cell->left == 0) { /* leaf reached */ if (str[j+1]) /* add non-leaf */ cell->left = new DictCell(str[j],0,false,true); else /* add leaf */ cell->left = new DictCell(str[j],value,true,false); cell = cell->left; continue; } /* if we reach this point we are at a non-leaf */ if (str[j] < cell->left->letter) { /* insert at beginning */ if (str[j+1]) /* add non-leaf */ cell->left = new DictCell(str[j],0,false,true,0,cell->left); else /* add leaf */ cell->left = new DictCell(str[j],value,true,false,0,cell->left); cell = cell->left; continue; } cell = cell->left; while (cell->right && (cell->right->letter <= str[j])) cell = cell->right; if (cell->letter < str[j]) { /* add new cell */ if (str[j+1]) /* add non-leaf */ cell->right = new DictCell(str[j],0,false,true,0,cell->right); else /* add leaf */ cell->right = new DictCell(str[j],value,true,false,0,cell->right); cell = cell->right; continue; } /* if we reach this point cell->letter = str[j] */ cell->uniquePrefix = false; if (str[j+1] == 0) { /* word is complete */ cell->fullname = true; cell->ptr = value; } } } template void Dictionary::remove(const String& str) /* Not implemented. */ {} }; /**************************************************************************** Chapter II -- The DictCell class. ****************************************************************************/ namespace dictionary { template DictCell::~DictCell() /* This destructor will recursively remove the dictionary. It is assumed that the dictionary owns its data. */ { delete left; delete right; delete ptr; } /* template void DictCell::operator delete(void* ptr, size_t size) { arena().free(ptr,size); } */ }; /****** Auxiliary functions ************************************************/ namespace dictionary { template void printExtensions(FILE* file, DictCell* cell, String& name, bool &first, const char* sep) /* This function prints all the possible extensions of the prefix corresponding to str on stdout. It is an auxiliary to the interactive treatment of ambiguities. It is assumed that name contains the name of the parent of the string. */ { if (cell == 0) return; append(name,cell->letter); if (cell->fullname) { /* print */ if (first) /* first time a name is found */ first = false; else fprintf(file,"%s",sep); fprintf(file,"%s",name.ptr()); } printExtensions(file,cell->left,name,first,sep); erase(name,1); printExtensions(file,cell->right,name,first,sep); } }; positivity_final/directories.h0000600000175000017500000000167610011171251020316 0ustar duclouxducloux00000000000000/* This is directories.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef DIRECTORIES_H /* guard against multiple inclusions */ #define DIRECTORIES_H /* This file tells where the directories can be found which contain some auxiliary files used by the program. The following directories are defined : - COXMATRIX_DIR : contains the files for predefined Coxeter matrices; these are the files that are loaded through the "X" group type. - HEADER_DIR : contains headers for the output to files done by some of the commands. - MESSAGE_DIR : contains the text of various error and warning messages. This is used mostly by the help facility, and also in some of the error handling. */ namespace directories { char* const COXMATRIX_DIR = "coxeter_matrices"; char* const HEADER_DIR = "headers"; char* const MESSAGE_DIR = "messages"; }; #endif positivity_final/dotval.h0000600000175000017500000000077310011171251017270 0ustar duclouxducloux00000000000000/* This is dotval.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef DOTVAL_H /* guard against multiple inclusions */ #define DOTVAL_H namespace dotval { enum DotVal { undef_dotval = -8, locked = -6, undef_negdot = -5, neg_cos = -4, neg_cos2 = -3, neg_half = -2, neg_hinvgold = -1, zero = 0, hinvgold = 1, half = 2, cos2 = 3, cos = 4, undef_posdot = 5, one = 6 }; }; #endif positivity_final/error.cpp0000600000175000017500000006053510246351027017500 0ustar duclouxducloux00000000000000/* This is error.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include #include "error.h" #include "coxtypes.h" #include "directories.h" #include "graph.h" #include "interactive.h" #include "interface.h" #include "io.h" #include "kl.h" #include "schubert.h" #include "version.h" namespace error { using namespace directories; using namespace io; using namespace interactive; using namespace interface; using namespace kl; using namespace coxtypes; using namespace graph; using namespace schubert; using namespace version; }; namespace error { bool CATCH_MEMORY_OVERFLOW = false; int ERRNO = 0; }; namespace { using namespace error; void abortError(); void badCoxEntry(); void badFile(); void badInput(char *s); void badLength(const long& l); void badLine(char *filename,Rank l,Rank i,Rank j); void badRCycField(); void checkminFail(); void commandRedefinition(char *a); void commandNotFound(char *a); void contextNbrOverflow(Ulong size); void coxAllocFail(); void coxNbrOverflow(); void denseArrayOverflow(Ulong size); void extensionFail(); void fileNotFound(char *s); void klCoeffNegative(const CoxNbr& x, const CoxNbr& y); void klCoeffOverflow(const CoxNbr& x, const CoxNbr& y); void klFail(const CoxNbr& x, const CoxNbr& y); void leadingWhitespace(const GroupEltInterface& I, const GroupEltInterface& J, const Permutation& a, const String& str); void lengthOverflow(); void memoryWarning(); void minRootOverflow(); void modeChangeFail(); void muFail(const KLContext& kl, const CoxNbr& x, const CoxNbr& y); void muNegative(const KLContext& kl, const CoxNbr& x, const CoxNbr& y); void muOverflow(const KLContext& kl, const CoxNbr& x, const CoxNbr& y); void notAffine(); void notCoxelt(); void notDescent(const char* str); void notFinite(); void notGenerator(); void notPermutation(); void notSymmetric(char *filename, CoxMatrix& m, Rank l, Rank i, Rank j); void outOfMemory(); void parNbrOverflow(); void parseError(const char* str); void repeatedSymbol(const GroupEltInterface& I, const GroupEltInterface& J, const Permutation& a); void reservedSymbol(const GroupEltInterface& I, const GroupEltInterface& J, const Permutation& a, const String& str); void ueMuFail(const CoxNbr& x, const CoxNbr& y); void undefCoxarr(); void wrongCoxeterEntry(Rank i, Rank j, Ulong m); void wrongRank(const Type& type, Rank* l, int* mess); void wrongType(); }; /******************************************************************** Chapter I --- General error handling functions ********************************************************************/ void error::Error(int number, ... ) /* This function dispatches the error messages to their respective handlers. Some are fatal, others non-fatal. ERRNO is reset to 0 at the beginning of the function (rather than at the end, which would seem more natural), so that the error handling is not perturbed by a non-zero value of ERRNO. Of course this means that the error-handling functions should only use calls which are safe in the given context. */ { va_list ap; ERRNO = 0; va_start(ap,number); switch (number) { case 0: break; case ABORT: abortError(); break; case BAD_COXENTRY: badCoxEntry(); break; case BAD_INPUT: { char *a = va_arg(ap,char *); badInput(a); } break; case BAD_LENGTH: { Ulong l = va_arg(ap,long); badLength(l); } break; case BAD_LINE: { char *filename = va_arg(ap,char *); Rank l = va_arg(ap,int); Rank i = va_arg(ap,int); Rank j = va_arg(ap,int); badLine(filename,l,i,j); } break; case BAD_RCYCFIELD: badRCycField(); break; case CHECKMIN_FAIL: checkminFail(); break; case COMMAND_NOT_FOUND: { char *a = va_arg(ap, char *); commandNotFound(a); } break; case COMMAND_REDEFINITION: { char *a = va_arg(ap, char *); commandRedefinition(a); } break; case CONTEXTNBR_OVERFLOW: { Ulong size = va_arg(ap,Ulong); contextNbrOverflow(size); } break; case COXALLOC_FAIL: coxAllocFail(); break; case COXNBR_OVERFLOW: coxNbrOverflow(); break; case DENSEARRAY_OVERFLOW: { Ulong size = va_arg(ap,Ulong); denseArrayOverflow(size); } break; case ERROR_WARNING: break; case EXTENSION_FAIL: extensionFail(); break; case FILE_NOT_FOUND: fileNotFound(va_arg(ap,char *)); break; case KLCOEFF_NEGATIVE: { CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); klCoeffNegative(x,y); } break; case KLCOEFF_OVERFLOW: { CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); klCoeffOverflow(x,y); } break; case KL_FAIL: { CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); klFail(x,y); } break; case LEADING_WHITESPACE: { const GroupEltInterface* I = va_arg(ap, const GroupEltInterface*); const GroupEltInterface* J = va_arg(ap, const GroupEltInterface*); const Permutation* a = va_arg(ap, const Permutation*); const String* str = va_arg(ap, const String*); leadingWhitespace(*I,*J,*a,*str); } break; case LENGTH_OVERFLOW: lengthOverflow(); break; case MEMORY_WARNING: memoryWarning(); break; case MINROOT_OVERFLOW: minRootOverflow(); break; case MODECHANGE_FAIL: modeChangeFail(); break; case MU_FAIL: { const KLContext& kl = *va_arg(ap, KLContext*); CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); muFail(kl,x,y); } break; case MU_OVERFLOW: { const KLContext& kl = *va_arg(ap, KLContext*); CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); muOverflow(kl,x,y); } break; case MU_NEGATIVE: { const KLContext& kl = *va_arg(ap, KLContext*); CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); muNegative(kl,x,y); } break; case NOT_AFFINE: notAffine(); break; case NOT_COXELT: notCoxelt(); break; case NOT_DESCENT: { const char* str = va_arg(ap,const char*); notDescent(str); break; } case NOT_FINITE: notFinite(); break; case NOT_GENERATOR: notGenerator(); break; case NOT_PERMUTATION: notPermutation(); break; case NOT_SYMMETRIC: { char *filename = va_arg(ap,char*); CoxMatrix& m = *va_arg(ap,CoxMatrix*); Rank l = va_arg(ap,int); Rank i = va_arg(ap,int); Rank j = va_arg(ap,int); notSymmetric(filename,m,l,i,j); } break; case OUT_OF_MEMORY: { outOfMemory(); } break; case PARNBR_OVERFLOW: parNbrOverflow(); break; case PARSE_ERROR: { const char* str = va_arg(ap,const char*); parseError(str); } break; case REPEATED_SYMBOL: { const GroupEltInterface* I = va_arg(ap, const GroupEltInterface*); const GroupEltInterface* J = va_arg(ap, const GroupEltInterface*); const Permutation* a = va_arg(ap, const Permutation*); repeatedSymbol(*I,*J,*a); } break; case RESERVED_SYMBOL: { const GroupEltInterface* I = va_arg(ap, const GroupEltInterface*); const GroupEltInterface* J = va_arg(ap, const GroupEltInterface*); const Permutation* a = va_arg(ap, const Permutation*); const String* str = va_arg(ap, const String*); reservedSymbol(*I,*J,*a,*str); } break; case UEMU_FAIL: { CoxNbr x = va_arg(ap, CoxNbr); CoxNbr y = va_arg(ap, CoxNbr); ueMuFail(x,y); } case UNDEF_COXARR: undefCoxarr(); break; case WRONG_COXETER_ENTRY: { Rank i = va_arg(ap,int); Rank j = va_arg(ap,int); Ulong m = va_arg(ap,Ulong); wrongCoxeterEntry(i,j,m); } break; case WRONG_RANK: { Type* t = va_arg(ap,Type*); Rank* l = va_arg(ap,Rank*); int* mess = va_arg(ap,int*); wrongRank(*t,l,mess); } break; case WRONG_TYPE: wrongType(); break; default: abortError(); break; } va_end(ap); return; } /******************************************************************** Chapter II --- Specific error handling functions. ********************************************************************/ namespace { void abortError() /* Handles the error ABORT (indicating that the user or the program choses to abort a command.) */ { fprintf(stderr,"aborted\n"); return; } void badCoxEntry() /* Handles the error BAD_COXENTRY; this means that a bad entry was detected in a Coxeter matrix (presumable during interactive input, or input from a file.) */ { fprintf(stderr,"sorry, bad entry in coxeter matrix\n"); return; } void badInput(char *s) { fprintf(stderr, "illegal character after this : (enter new input, ? to abort)\n"); printf("%s",s); return; } void badLength(const long& l) /* Handles the error BAD_LENGTH. This means that the user has entered a length which (after automatic conversion to unsigned long) is not in the range [0,LENGTH_MAX]. */ { fprintf(stderr,"bad length value; should be between 0 and %lu\n", static_cast(LENGTH_MAX)); fprintf(stderr,"value read was %ld\n",l); return; } void badLine(char *filename,Rank l,Rank i,Rank j) /* Handles the error BAD_LINE. The first argument is the line number for which the error happened, the second the rank of the group. This error occurs when the corresponding line in the matrix was too short. */ { fprintf(stderr,"error : line #%lu too short in %s/%s\n", static_cast(i+1),COXMATRIX_DIR,filename); if (j == 1) fprintf(stderr,"one entry found; %lu entries expected\n", static_cast(l)); else fprintf(stderr,"%lu entries found; %lu entries expected\n", static_cast(j),static_cast(l)); return; } void badRCycField() { fprintf(stderr,"Illegal variation parameter in RCyclotomicField\n"); return; } void checkminFail() /* Handles error CHECKMIN_FAIL. This means that the checking of finite order in the minimal root construction didn't go through. */ { fprintf(stderr,"error : failure in checkMinimal\n"); return; } void commandNotFound(char *a) /* Handles error COMMAND_NOT_FOUND. This means that a was not recognized as an (even partial) command name. */ { fprintf(stderr,"%s : not found in current mode\n",a); return; } void commandRedefinition(char *a) /* Handles error COMMAND_REDEFINITION. This means that some command name is redefined. It is not considered to be an error, but a warning message is printed. */ { fprintf(stderr,"warning : redefining command \"%s\"\n",a); return; } void contextNbrOverflow(Ulong size) /* Handles the error CONTEXTNBR_OVERFLOW. This means that a number couldn't represent an element of the current context because it was too big. */ { fprintf(stderr,"number too big --- %lu is the limit\n",size-1); return; } void coxAllocFail() /* Handles the error COXALLOC_FAIL. This means that the allocation of a coxgroup structure failed (because of bad input by the user, overflow of some kind ... ) */ { fprintf(stderr,"error : allocation failed\n"); return; } void coxNbrOverflow() /* Handles the error COXNBR_OVERFLOW. This means that an element was found somewhere that should have been represented by a CoxNbr, but couldn't because it was too big. */ { fprintf(stderr,"error : CoxNbr overflow\n"); return; } void denseArrayOverflow(Ulong size) /* Handles the error DENSEARRAY_OVERFLOW. This means that a number couldn't represent an element of the current group because it was too big. */ { fprintf(stderr,"number too big --- %lu is the limit\n",size-1); return; } void extensionFail() /* Handles the error EXTENSION_FAIL. This means that the extension of the kl context failed (due to overflow in a number, a length, or more likely, due to an out-of-memory condition.) */ { fprintf(stderr,"error : could not extend the context\n"); return; } void fileNotFound(char *s) /* Handles the error FILE_NOT_FOUND; this happens when a filename is requested from the user for input purposes, and the file is not found. */ { fprintf(stderr,"%s : file not found\n",s); return; } void klCoeffNegative(const CoxNbr& x, const CoxNbr& y) /* Handles the error KLCOEFF_NEGATIVE. This means that a negative coefficient occurred in a Kazhdan-Lusztig polynomial. If this is not due to a bug in the program, it is a major discovery! NOTE : it is known that all k-l polynomials have positive coefficients for Weyl group of finite or Kac-Moody Lie algebras; also for the free Coxeter group, and for types H3 and H4 (and of course for all dihedral groups). So in these cases this error is definitely due to a bug int the program. */ { fprintf(stderr, "A negative coefficient occurred in a Kazhdan-Lusztig polynomial\n"); fprintf(stderr,"(x = %s%lu, y = %s%lu)\n","%", static_cast(x),"%",static_cast(y)); printFile(stderr,"neg_coeff.err",MESSAGE_DIR); return; } void klCoeffOverflow(const CoxNbr& x, const CoxNbr& y) /* Handles the error KLCOEFF_OVERFLOW; this means that in the course of the computation of a coefficient in a k-l polynomial, an overflow occurred (this will then always happen during the computation of P_{xs,ys}+P_{x,ys}) NOTE : it would be slightly better to trigger this error only if the overflow occurs in the actual value of the coefficient; to do this rigorously without using types bigger than KLCoeff is a bit more than I'm willing to cope with right now. We'll see about it when it becomes a real problem. NOTE : the output of x and y should be improved, as in klFail! */ { fprintf(stderr, "Overflow in the coefficients of Kazhdan-Lusztig polynomial\n"); fprintf(stderr,"(x = %s%lu, y = %s%lu)\n","%",static_cast(x),"%", static_cast(y)); return; } void klFail(const CoxNbr& x, const CoxNbr& y) /* Handles the error KL_FAIL. This means that an error occurred during the computation of a Kazhdan-Lusztig polynomial : either there was a memory overflow, or a negative coefficient was found. */ { fprintf(stderr, "error in the computation of the Kazhdan-Lusztig polynomial\n"); fprintf(stderr,"(x = %s%lu, y = %s%lu)\n","%",static_cast(x),"%", static_cast(y)); return; } void leadingWhitespace(const GroupEltInterface& I, const GroupEltInterface& J, const Permutation& a, const String& str) /* Handles the error LEADING_WHITESPACE; this means that I contains a symbol starting with whitespace. */ { fprintf(stderr, "error: one of the new input symbols begins with whitespace\n"); fprintf(stderr,"these are the symbols you submitted :\n\n"); printInterface(stderr,I,J,a); fprintf(stderr,"\nsymbol \""); print(stderr,str); fprintf(stderr,"\" begins with whitespace\n"); fprintf(stderr, "interface not modified. Please change offending symbol or abort.\n"); } void lengthOverflow() /* Handles the error LENGTH_OVERFLOW; does nothing for now. */ { return; } void memoryWarning() /* Handles the error MEMORY_WARNING. This means that there was an out-of-memory condition, which occured while CATCH_MEMORY_ERROR was turned on. Hopefully the situation was handled successfully (the offending computation was aborted, and the situation reverted to its previous state), so a simple message is printed. */ { fprintf(stderr,"sorry, insufficient memory\n"); return; } void minRootOverflow() /* Handles the error MINROOT_OVERFLOW; this means that the size of the minroot table exceeds its bound. */ { fprintf(stderr,"error : overflow in size of minroot table\n"); return; } void modeChangeFail() /* Handles the error MODECHANGE_FAIL; this means that an error occurred during the initialization function of a new mode. */ { fprintf(stderr,"aborted\n"); return; } void muFail(const KLContext& kl, const CoxNbr& x, const CoxNbr& y) /* Handles the error MU_FAIL : this means that an error occurred during the computation of a mu-coefficient. */ { fprintf(stderr,"error in the computation of a mu-coefficient\n"); fprintf(stderr,"(x = %s%lu, y = %s%lu)\n","%",static_cast(x),"%", static_cast(y)); return; } void muNegative(const KLContext& kl, const CoxNbr& x, const CoxNbr& y) /* Handles the error MU_NEGATIVE; this means that a negative mu-coefficient was found. Even more remarkable than a negative coefficient in a k-l polynomial! */ { fprintf(stderr,"Negative value in the computation of a mu-coeffient\n"); fprintf(stderr,"(x = %s%lu, y = %s%lu)\n","%",static_cast(x),"%", static_cast(y)); printFile(stderr,"neg_coeff.err",MESSAGE_DIR); return; } void muOverflow(const KLContext& kl, const CoxNbr& x, const CoxNbr& y) /* Handles the error MU_OVERFLOW; this means that overflow has occurred during the computation of a mu-coefficient. Very unlikely! */ { fprintf(stderr,"Overflow in the computation of a mu-coeffient\n"); fprintf(stderr,"(x = %s%lu, y = %s%lu)\n","%",static_cast(x),"%", static_cast(y)); return; } void notAffine() /* Handles the error NOT_AFFINE. This means that W->type() was not recognized as the type of an affine group. */ { fprintf(stderr,"error : type of group is not affine\n"); return; } void notCoxelt() /* Handles the error NOT_COXELT. This means that the user input was not recognized as a Coxeter element. */ { fprintf(stderr,"error : not a Coxeter element\n"); return; } void notDescent(const char* str) /* Handles the error NOT_DESCENT; this means in the function getGenerator(W,f), a generator has been proposed that is not flagged by f. The string typically holds the successfully parsed part of the input. */ { fprintf(stderr,"that is not a descent generator for y\n"); fprintf(stderr,"enter new input or ? to abort\n"); fprintf(stderr,"%s",str); return; } void notFinite() /* Handles the error NOT_FINITE. This means that W->type() was not recognized as the type of a finite group. */ { fprintf(stderr,"error : type of group is not finite\n"); return; } void notGenerator() /* Handles the error NOT_GENERATOR. This means that the user input was not recognized as a generator symbol. */ { fprintf(stderr,"error : not a generator symbol\n"); return; } void notPermutation() /* Handles the error NOT_PERMUTATION. This means that the user input was not recognized as the representation of a permutation (for type A only). */ { fprintf(stderr,"error : that is not a permutation\n"); return; } void notSymmetric(char *filename,CoxMatrix& m,Rank l,Rank i, Rank j) /* Handles the error NOT_SYMMETRIC. This means that j < i, and that m[i,j] != m[j,i] in the coxeter matrix being read from the file. */ { fprintf(stderr,"error : %s/%s not symmetric\n",COXMATRIX_DIR,filename); fprintf(stderr,"m[%lu,%lu] = %lu; m[%lu,%lu] = %lu\n", static_cast(i+1),static_cast(j+1), static_cast(m[i*l + j]),static_cast(j+1), static_cast(i+1),static_cast(m[j*l + i])); return; } void outOfMemory() /* Handles out-of-memory errors, unless CATCH_MEMORY_OVERFLOW is set. Fatal error. */ { if (CATCH_MEMORY_OVERFLOW) { /* error is handled elsewhere */ ERRNO = MEMORY_WARNING; return; } fprintf(stderr,"memory allocation failed\n"); fprintf(stderr,"memory usage :\n\n"); memory::arena().print(stderr); exit(0); } void parNbrOverflow() /* Handles the error PARNBR_OVERFLOW; simply prints an error message. */ { fprintf(stderr,"warning : overflow in the automaton construction\n"); return; } void parseError(const char* str) /* Handles the error PARSE_ERROR; this means that a parsing error has occurred during an input operation. The string typically holds the successfully parsed part of the input. */ { fprintf(stderr,"parse error after this : (enter new input or ? to abort)\n"); fprintf(stderr,"%s",str); return; } void reservedSymbol(const GroupEltInterface& I, const GroupEltInterface& J, const Permutation& a, const String& str) /* Handles the error RESERVED_SYMBOL; this means that I contains a symbol that was reserved by the ambient interface. */ { fprintf(stderr, "error: new interface contains a reserved symbol\n"); fprintf(stderr,"these are the symbols you submitted :\n\n"); printInterface(stderr,I,J,a); fprintf(stderr,"\nsymbol \""); print(stderr,str); fprintf(stderr,"\" is reserved\n"); fprintf(stderr, "interface not modified. Please change reserved symbol or abort.\n"); } void repeatedSymbol(const GroupEltInterface& I, const GroupEltInterface& J, const Permutation& a) /* Handles the error REPEATED_SYMBOL; this means that I contains repeated non-empty strings. */ { fprintf(stderr, "error: new interface contains non-empty repeated symbols\n"); fprintf(stderr,"these are the symbols you submitted :\n\n"); printInterface(stderr,I,J,a); fprintf(stderr, "\ninterface not modified. Please eliminate repetitions or abort.\n"); } void ueMuFail(const CoxNbr& x, const CoxNbr& y) /* Handles the error UEMU_FAIL : this means that an error occurred during the computation of a mu-coefficient with unequal parameters. NOTE : prints out the context numbers; the actual expressions would have to be gotten by the user using "compute". */ { fprintf(stderr,"error in the computation of a mu-coefficient\n"); fprintf(stderr,"(x = %s%lu; ","%",static_cast(x)); fprintf(stderr,"y = %s%lu)\n","%",static_cast(y)); fprintf(stderr, "use %ccompute%c to get reduced expressions from these context numbers\n", '"','"'); return; } void undefCoxarr() /* Handles the error UNDEF_COXARR; prints an error message. */ { fprintf(stderr,"error : undefined coxarr encountered\n"); return; } void wrongCoxeterEntry(Rank i, Rank j, Ulong m) { if (i == j) { fprintf(stderr,"\nDiagonal matrix entries should be 1\n"); return; } fprintf(stderr,"\nMatrix entry (%d,%d) out of range; should be 0 or lie between 2 and %u",i,j,COXENTRY_MAX); fprintf(stderr,"\nValue read was %lu\n",m); return; } void wrongRank(const Type& type, Rank *l, int *mess) { switch (type[0]) { case 'A': fprintf(stderr,"\nIn type %c the rank should lie between 1 and %d\n", type[0],RANK_MAX); break; case 'B': case 'D': fprintf(stderr,"\nIn type %c the rank should lie between 2 and %d\n", type[0],RANK_MAX); break; case 'E': fprintf(stderr,"\nIn type E the rank should lie between 3 and 8\n"); break; case 'F': fprintf(stderr,"\nIn type F the rank should be 3 or 4\n"); break; case 'G': fprintf(stderr,"\nIn type G the rank should be 2, so I'm setting it to 2\n\n"); l[0] = 2; mess[0] = 1; break; case 'H': fprintf(stderr,"\nIn type H the rank should lie between 2 and 4\n"); break; case 'I': fprintf(stderr,"\nIn type I the rank should be 2, so I'm setting it to 2\n\n"); l[0] = 2; mess[0] = 1; break; case 'a': fprintf(stderr,"\nIn type %c the rank should lie between 2 and %d\n", type[0],RANK_MAX); break; case 'b': case 'c': fprintf(stderr,"\nIn type %c the rank should lie between 3 and %d\n", type[0],RANK_MAX); break; case 'd': fprintf(stderr,"\nIn type %c the rank should lie between 5 and %d\n", type[0],RANK_MAX); break; case 'e': fprintf(stderr,"\nIn type e the rank should lie between 7 and 9\n"); break; case 'f': fprintf(stderr,"\nIn type f the rank should be 5, so I'm setting it to 5\n\n"); l[0] = 5; mess[0] = 1; break; case 'g': fprintf(stderr,"\nIn type g the rank should be 3, so I'm setting it to 3\n\n"); l[0] = 3; mess[0] = 1; break; case 'X': case 'x': fprintf(stderr,"\nIn type %c the rank should lie between 1 and %d\n", type[0],RANK_MAX); break; } return; } void wrongType() /* Handles the error WRONG_TYPE. This means that the user has entered an illegal type. */ { printFile(stderr,"wrongtype.mess",MESSAGE_DIR); return; } }; positivity_final/error.h0000600000175000017500000000271310011171251017124 0ustar duclouxducloux00000000000000/* This is error.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef ERROR_H /* guard against multiple inclusions */ #define ERROR_H #include "globals.h" namespace error { using namespace globals; }; namespace error { enum ErrorCodes { ABORT=1, BAD_COXENTRY, BAD_INPUT, BAD_LENGTH, BAD_LINE, BAD_RCYCFIELD, CHECKCOMM_FAIL, CHECKMIN_FAIL, COMMAND_NOT_FOUND, COMMAND_REDEFINITION, CONTEXTNBR_OVERFLOW, COXALLOC_FAIL, COXNBR_OVERFLOW, DENSEARRAY_OVERFLOW, EMPTY_POP, EMPTY_READ, ERROR_WARNING, EXTENSION_FAIL, FILE_NOT_FOUND, LEADING_WHITESPACE, LENGTH_OVERFLOW, KLCOEFF_OVERFLOW, KLCOEFF_NEGATIVE, KLCOEFF_UNDERFLOW, KL_FAIL, MEMORY_WARNING, MINROOT_FAIL, MINROOT_OVERFLOW, MODECHANGE_FAIL, MU_FAIL, MU_NEGATIVE, MU_OVERFLOW, NOT_AFFINE, NOT_COXELT, NOT_DESCENT, NOT_FINITE, NOT_GENERATOR, NOT_PERMUTATION, NOT_SYMMETRIC, NOT_YN, OUT_OF_MEMORY, PARNBR_OVERFLOW, PARSE_ERROR, RANKSET_FAILED, READ_FAILED, REPEATED_SYMBOL, RESERVED_SYMBOL, SKLCOEFF_OVERFLOW, SKLCOEFF_UNDERFLOW, TYPESET_FAILED, UEMU_FAIL, UNDEF_COXARR, UNDEFINED_SHIFT, WRONG_COXETER_ENTRY, WRONG_RANK, WRONG_TYPE }; extern bool CATCH_MEMORY_OVERFLOW; extern int ERRNO; void Error(int number, ... ); }; #endif positivity_final/fcoxgroup.cpp0000600000175000017500000007125010012716277020362 0ustar duclouxducloux00000000000000/* This is fcoxgroup.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "fcoxgroup.h" #include "cells.h" #define undefined (ParNbr)(PARNBR_MAX + 1) namespace fcoxgroup { using namespace cells; }; /* local type definitions */ namespace { using namespace fcoxgroup; class Workspace { List d_ica_arr; List d_nfca_arr; List d_prca_arr; List d_rdcw_arr; public: Workspace(); void setSize(Ulong n); ParNbr *ica_arr() {return d_ica_arr.ptr();} ParNbr *nfca_arr() {return d_nfca_arr.ptr();} ParNbr *prca_arr() {return d_prca_arr.ptr();} ParNbr *rdcw_arr() {return d_rdcw_arr.ptr();} }; void fillLongest(FiniteCoxGroup *W); CoxSize order(FiniteCoxGroup *W); Workspace& workspace(); }; /**************************************************************************** NOTE : unfinished. This file contains code for dealing more efficiently with finite Coxeter groups. There are two representations of group elements which are more compact than the CoxWord representation. The first one, which will work for any rank <= 255, represents the elements as arrays of rank ParNbr's. The computations in this representation are made through a cascade of small transducers. The drawback of this representation is that the size of the automata depends strongly on the choice of ordering (as opposed to the minimal root machine, which is completely canonical.) ... Our allocation of workspace avoids having to check the sizes at each operation; it is not so clear however if this really makes a difference. ****************************************************************************/ /**************************************************************************** Chapter 0 -- Initialization. ****************************************************************************/ namespace { Workspace::Workspace() :d_ica_arr(), d_nfca_arr(), d_prca_arr(), d_rdcw_arr() {} void Workspace::setSize(Ulong n) { d_ica_arr.setSize(n); d_nfca_arr.setSize(n); d_prca_arr.setSize(n); d_rdcw_arr.setSize(n); return; } inline Workspace& workspace() /* Returns its static object, which is initialized on first call. */ { static Workspace wspace; return wspace; } }; /**************************************************************************** Chapter I -- The FiniteCoxGroup class. This section defines the FiniteCoxGroup class. The following functions are defined : - FiniteCoxGroup(x,l) : constructor; - assign(a,g) : sets a to the array form of g; - duflo() : returns the list of Duflo involutions; - inverse(a) : inverses a; - isFullContext() : tells if longest_elt is in context; - l(r,lr)Cell() : returns the partition in left (right,two-sided) cells; - l(r,lr)UneqCell() : returns the partition in left (right,two-sided) cells for unequal parameters; - l(r)Descent() : returns the partition in left (right) descent classes; - l(r)String() : returns the partition in left (right) string classes; - l(r)Tau() : returns the partition in left (right) generalized tau classes; - length() : returns the length of a; - normalForm(g,a) : returns the ShortLex normal form of a in g; - normalForm(g,h) : returns the ShortLex normal form of h in g; - parseModifier(P) : parses a modifier; - prod(a,b) : increments a by b; - prod(a,s) : puts in a the result of a.s; - prod(a,g) : puts in a the result of a.g; - power(a,m) : sets a to the power m; - rDescent(a) : returns the right descent set of the coxarr a; - reduced(g,a) : puts a reduced expression for a in g; ****************************************************************************/ namespace fcoxgroup { /******** constructor *******************************************************/ FiniteCoxGroup::FiniteCoxGroup(const Type& x, const Rank& l) :CoxGroup(x,l) /* Constructor for FiniteCoxGroup. */ { d_transducer = new Transducer(graph()); workspace().setSize(l); for (Rank j = 0; j < rank(); ++j) transducer(j)->fill(graph()); d_longest_coxarr = new(arena()) ParNbr[rank()]; /* fill longest elements */ for (FiltrationTerm* X = transducer(); X; X = X->next()) d_longest_coxarr[X->rank()-1] = X->size()-1; Ulong maxlength = length(d_longest_coxarr); new(&d_longest_coxword) CoxWord(maxlength); reducedArr(d_longest_coxword,d_longest_coxarr); d_longest_coxword.setLength(maxlength); d_maxlength = longest_coxword().length(); d_order = ::order(this); } FiniteCoxGroup::~FiniteCoxGroup() /* The only thing that the FiniteCoxGroup destructor has to do explicitly is to delete the transducer table, and d_longest. */ { arena().free(d_longest_coxarr,rank()*sizeof(ParNbr)); delete d_transducer; return; } /******** general ***********************************************************/ bool FiniteCoxGroup::isFullContext() const /* Tells if the longest element is in the context. If so, it is necessarily the last element fo the context, and can be recognized from its left descent set. */ { CoxNbr x = schubert().size()-1; LFlags f = ldescent(x); if (f == graph().supp()) return true; else return false; } /******** operations with arrays ********************************************/ const CoxArr& FiniteCoxGroup::assign(CoxArr& a, const CoxWord& g) const /* This functions returns the array-form of the element of W represented by the word g. It returns the result in a. */ { setZero(a); for(Length i = 0; g[i]; ++i) prodArr(a,g[i]-1); return a; } const CoxArr& FiniteCoxGroup::inverseArr(CoxArr& a) const /* Inverse a. This is a "composite-assignment" type function, in consistency with our geneeral philosophy that they're the only ones really needed. Uses ica_arr() as workspace. */ { CoxArr b = workspace().ica_arr(); assign(b,a); setZero(a); for (const FiltrationTerm* X = transducer(); X; X = X->next()) { const CoxWord& g = X->np(b[X->rank()-1]); Ulong j = g.length(); while (j) { j--; prodArr(a,g[j]-1); } } return a; } Length FiniteCoxGroup::length(const CoxArr& a) const /* Returns the length of a --- overflow is not checked. */ { Length c = 0; for (const FiltrationTerm* X = transducer(); X; X = X->next()) { ParNbr x = a[X->rank()-1]; c += X->length(x); } return c; } const CoxArr& FiniteCoxGroup::powerArr(CoxArr& a, const Ulong& m) const /* Raises a to the m-th power. This can be done very quickly, by squarings and multiplications with the original value of a (stored in b), by looking at the bit-pattern of m. */ { static Ulong hi_bit = (Ulong)1 << BITS(Ulong) - 1; static List buf(0); if (m == 0) return a; buf.setSize(rank()); CoxArr b = buf.ptr(); Ulong p; assign(b,a); for (p = m; ~p & hi_bit; p <<= 1) /* shift m up to high powers */ ; for (Ulong j = m >> 1; j; j >>= 1) { p <<= 1; prodArr(a,a); /* a = a*a */ if (p & hi_bit) prodArr(a,b); /* a = a*b */ } return a; } int FiniteCoxGroup::prodArr(CoxArr& a, const CoxArr& b) const /* Composite assignment operator : increments a by b (i.e., does a *= b). The algorithm goes by shifting by the successive pieces of the normal form of b, which are directly accessible. Uses prca_arr() as workspace; */ { CoxArr c = workspace().prca_arr(); assign(c,b); int l = 0; for (Ulong j = 0; j < rank(); ++j) l += prodArr(a,transducer(rank()-1-j)->np(c[j])); return l; } int FiniteCoxGroup::prodArr(CoxArr& a, Generator s) const /* Transforms the contents of a into a.s. */ { for (const FiltrationTerm* X = transducer(); X; X = X->next()) { ParNbr x = a[X->rank()-1]; ParNbr xs = X->shift(a[X->rank()-1],s); if (xs < undefined) { a[X->rank()-1] = xs; if (xs < x) return -1; else return 1; } s = xs - undefined - 1; } return 0; // this is unreachable } int FiniteCoxGroup::prodArr(CoxArr& a, const CoxWord& g) const /* Shifts a by the whole string g. Returns the increase in length. */ { int l = 0; for (Length j = 0; g[j]; ++j) l += prodArr(a,g[j]-1); return l; } LFlags FiniteCoxGroup::rDescent(const CoxArr& a) const /* Returns the right descent set of a. NOTE : makes sense only when the rank is at most MEDRANK_MAX. */ { LFlags f = 0; for (Generator s = 0; s < rank(); s++) /* multiply by s */ { Generator t = s; for (const FiltrationTerm* X = transducer(); X; X = X->next()) { ParNbr x = a[X->rank()-1]; ParNbr xt = X->shift(x,t); if (xt <= undefined) { /* we can decide */ if (xt < x) f |= bits::lmask[s]; break; } t = xt - undefined - 1; } } return f; } const CoxWord& FiniteCoxGroup::reducedArr(CoxWord& g, const CoxArr& a) const /* Returns in g a reduced expression (actually the ShortLex normal form in the internal numbering of the generators) of a. Here it is assumed that g is large enough to hold the result. */ { Length p = length(a); g[p] = '\0'; for (const FiltrationTerm* X = transducer(); X; X = X->next()) { ParNbr x = a[X->rank()-1]; p -= X->length(x); g.setSubWord(X->np(x),p,X->length(x)); } return g; } /******** input/output ******************************************************/ void FiniteCoxGroup::modify(ParseInterface& P, const Token& tok) const /* Executes the modification indicated by tok, which is assumed to be of type modifier_type. It is possible that further characters may have to be read from str. In the case of a finite coxeter group, three modifies are allowed : *, ! and ^ */ { if (isLongest(tok)) { CoxGroup::prod(P.c,d_longest_coxword); } if (isInverse(tok)) { CoxGroup::inverse(P.c); } if (isPower(tok)) { Ulong m = readCoxNbr(P,ULONG_MAX); CoxGroup::power(P.c,m); } } bool FiniteCoxGroup::parseModifier(ParseInterface& P) const /* This function parses a modifier from P.str at P.offset, and acts upon it accordingly : in case of success, it applies the modifier to P.c, and advances the offset. In the case of a finite group, multiplication by the longest element is allowed. */ { Token tok = 0; const Interface& I = interface(); Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isModifier(tok)) return false; P.offset += p; modify(P,tok); return true; } /******** kazhdan-lusztig cells *********************************************/ const List& FiniteCoxGroup::duflo() /* This function returns the list of Duflo involutions in the group, in the order in which left cells are listed in lCell : duflo[j] is the Duflo involution in the j-th cell of d_lcell. The algorithm is as follows. We partition the involutions in the group according to the left cell partition. Then the Duflo involution in the cell is the unique involution for which l(w)-2d(w) is minimal, where d(w) is the degree of the Kazhdan-Lusztig polynomial P_{1,w}. NOTE : as for the l(r,lr)cell partitions, the list is filled upon the first call. */ { kl::KLContext& kl = d_kl[0]; const SchubertContext& p = kl.schubert(); SubSet q(0); /* make sure left cell partition is available */ lCell(); /* load involutions in q */ q.bitMap().assign(kl.involution()); q.readBitMap(); if (d_duflo.size() == 0) { /* find duflo involutions */ /* partition involutions by left cells */ Partition pi(q.size()); for (Ulong j = 0; j < q.size(); ++j) { pi[j] = d_lcell[q[j]]; } pi.setClassCount(d_lcell.classCount()); /* find Duflo involution in each cell */ for (PartitionIterator i(pi); i; ++i) { const List& c = i(); if (c.size() == 1) { /* cell has single involution */ d_duflo.append(q[c[0]]); continue; } Length m = d_maxlength; CoxNbr d = c[0]; for (Ulong j = 0; j < c.size(); ++j) { CoxNbr x = q[c[j]]; /* current involution */ const kl::KLPol& pol = kl.klPol(0,x); Length m1 = p.length(x) - 2*pol.deg(); if (m1 < m) { m = m1; d = x; } } d_duflo.append(d); } } return d_duflo; } const Partition& FiniteCoxGroup::lCell() /* Returns the partition into left cells, making it from the right cell partitition. */ { if (d_lcell.classCount()) /* partition was already computed */ return d_lcell; const Partition& r = rCell(); d_lcell.setSize(r.size()); d_lcell.setClassCount(r.classCount()); for (CoxNbr x = 0; x < r.size(); ++x) { d_lcell[x] = r(CoxGroup::inverse(x)); } d_lcell.normalize(); return d_lcell; } const Partition& FiniteCoxGroup::lrCell() /* Similar to rCell, but for two-sided cells. */ { if (d_lrcell.classCount()) /* partition was already computed */ return d_lrcell; if (!isFullContext()) { fullContext(); if (ERRNO) goto abort; kl().fillMu(); if (ERRNO) goto abort; } if (d_lrcell.size() == 0) /* size is either zero or group order */ cells::lrCells(d_lrcell,kl()); return d_lrcell; abort: Error(ERRNO); return d_lrcell; } const Partition& FiniteCoxGroup::lrUneqCell() /* Similar to lCell, but for two-sided cells. */ { if (d_lruneqcell.classCount()) /* partition was already computed */ return d_lruneqcell; if (!isFullContext()) { fullContext(); if (ERRNO) goto abort; uneqkl().fillMu(); if (ERRNO) goto abort; } { OrientedGraph X(0); lrGraph(X,uneqkl()); X.cells(d_lruneqcell); } return d_lruneqcell; abort: Error(ERRNO); return d_lruneqcell; } const Partition& FiniteCoxGroup::lUneqCell() /* Returns the partition in left cells for unequal parameters. The partition is gotten from the right one, by inversing. */ { if (d_luneqcell.classCount()) /* partition was already computed */ return d_luneqcell; const Partition& r = rUneqCell(); d_luneqcell.setSize(r.size()); d_luneqcell.setClassCount(r.classCount()); for (CoxNbr x = 0; x < r.size(); ++x) { d_luneqcell[x] = r(CoxGroup::inverse(x)); } d_luneqcell.normalize(); return d_luneqcell; } const Partition& FiniteCoxGroup::rCell() /* This function returns the partition of the group in right cells. NOTE : to be on the safe side, we allow this function to respond only for the full group context. If the context is not full, it extends it first to the full group. NOTE : because this is a potentially very expensive operation, the partition is computed on request. NOTE : since it is not clear that the ordering in which rCells constructs the cells is meaningful, we normalize the partition, so that it can be guaranteed to always have the same meaning. */ { if (d_rcell.classCount()) /* partition was already computed */ return d_rcell; if (!isFullContext()) { fullContext(); if (ERRNO) goto abort; } kl().fillMu(); if (ERRNO) goto abort; cells::rCells(d_rcell,kl()); d_rcell.normalize(); return d_rcell; abort: Error(ERRNO); return d_rcell; } const Partition& FiniteCoxGroup::rUneqCell() /* This function returns the partition of the group in right cells for unequal parameters. NOTE : to be on the safe side, we allow this function to respond only for the full group context. If the context is not full, it extends it first to the full group. NOTE : because this is a potentially very expensive operation, the partition is computed on request. */ { if (d_runeqcell.classCount()) /* partition was already computed */ return d_runeqcell; if (!isFullContext()) { fullContext(); if (ERRNO) goto abort; } d_uneqkl->fillMu(); if (ERRNO) goto abort; { OrientedGraph Y(0); rGraph(Y,uneqkl()); Y.cells(d_runeqcell); d_runeqcell.normalize(); } return d_runeqcell; abort: Error(ERRNO); return d_runeqcell; } const Partition& FiniteCoxGroup::lDescent() /* Returns the partition of the group in left descent classes, where two elements are equivalent iff they have the same left descent set (this is the non-generalized tau-invariant of Vogan.) It is known that this partition is coarser than the one by right cells. */ { if (d_ldescent.classCount()) /* partition was already computed */ return d_ldescent; if (!isFullContext()) { fullContext(); if (ERRNO) goto abort; } d_ldescent.setSize(order()); for (CoxNbr x = 0; x < order(); ++x) d_ldescent[x] = ldescent(x); d_ldescent.setClassCount(1<next()) { x *= X->size(); x += a[X->rank()-1]; } } bool SmallCoxGroup::parseDenseArray(ParseInterface& P) const /* Tries to parse a DenseArray from P. This is a '#' character, followed by an integer which has to lie in the range [0,N[, where N is the size of the group. */ { const Interface& I = interface(); Token tok = 0; Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isDenseArray(tok)) return false; // if we get to this point, we must read a valid integer P.offset += p; CoxNbr x = interface::readCoxNbr(P,d_order); if (x == undef_coxnbr) { //error P.offset -= p; Error(DENSEARRAY_OVERFLOW,d_order); ERRNO = PARSE_ERROR; } else { // x is valid CoxWord g(0); prodD(g,x); CoxGroup::prod(P.c,g); } return true; } bool SmallCoxGroup::parseGroupElement(ParseInterface& P) const /* This is the parseGroupElement function for the SmallCoxGroup type. In this class, we have one additional representation of elements, viz. the densearray representation. This means that an element that would be represented by the array [x_1, ... ,x_n] is represented by the number w = x_1+x_2*a_1+ ... +x_n*a_{n-1}, where a_j is the size of the j'th subgroup in the filtration. This will give a bijective correspondence between group elements and numbers in the range [0,N-1], where N is the size of the group. */ { Ulong r = P.offset; if (parseContextNumber(P)) { // next token is a context number if (ERRNO) // parse error return true; else goto modify; } if (parseDenseArray(P)) { // next token is a dense array if (ERRNO) // parse error return true; else goto modify; } // if we get to this point, we have to read a CoxWord interface().parseCoxWord(P,mintable()); if (ERRNO) { // no CoxWord could be parsed if (P.offset == r) { // nothing was parsed ERRNO = 0; return false; } else // parse error return true; } modify: // if we get to this point, a group element was successfully read while (parseModifier(P)) { if (ERRNO) return true; } // flush the current group element prod(P.a[P.nestlevel],P.c); P.c.reset(); if (P.offset == r) // nothing was read; c is unchanged return false; else return true; } int SmallCoxGroup::prodD(CoxWord& g, const DenseArray& d_x) const /* Does the multiplication of g by x, by recovering the normal pieces of x. returns the length increase. */ { const Transducer& T = d_transducer[0]; DenseArray x = d_x; int l = 0; for (Ulong j = 0; j < rank(); ++j) { const FiltrationTerm& X = T.transducer(rank()-1-j)[0]; ParNbr c = x%X.size(); l += CoxGroup::prod(g,X.np(c)); x /= X.size(); } return l; } int SmallCoxGroup::prodD(DenseArray& x, const CoxWord& g) const /* Does the multiplication of x by g. */ { static List al(0); al.setSize(rank()); CoxArr a = al.ptr(); assign(a,x); int l = prodArr(a,g); assign(x,a); return l; } }; /**************************************************************************** Chapter III -- Auxiliary functions. This section contains some auxiliary functions for the construction of finite Coxeter groups. The following functions are defined : - fillLongest(W) : fills in the longest element; - order(W) : returns the order of the group; ****************************************************************************/ namespace { void fillLongest(FiniteCoxGroup *W) /* Initializes the following constants : - W->longest_coxarr : array form of the longest element in W; - W->longest_coxword : string form of the longest element in W; */ { return; } CoxSize order(FiniteCoxGroup *W) /* This function fills in the order of W. It sets order to the order of W if the order is <= COXSIZE_MAX, sets it to 0 (for the time being) otherwise. Assumes that the order of subgroup has been filled in already. */ { CoxSize order = 1; for (const FiltrationTerm* X = W->transducer(); X; X = X->next()) { if (X->size() > COXSIZE_MAX/order) /* overflow */ return 0; order *= X->size(); } return order; } }; /**************************************************************************** Chapter IV -- Types and sizes. This section regroups some auxiliary functions for type recognition and size computations. The functions provided are : - isFiniteType(W) : recognizes a finite group --- defines the notion of a finite group in this program. - maxSmallRank : the maximum rank for a SmallCoxGroup on the current machine; ****************************************************************************/ bool fcoxgroup::isFiniteType(CoxGroup *W) /* Recognizes the type of a finite group. Non-irreducible types are allowed; they are words in the irreducible types. This function defines the class of groups that will be treated as finite groups in this program; the i/o setup is flexible enough that there is no reason that a finite group should be entered otherwise. */ { return isFiniteType(W->type()); } Rank fcoxgroup::maxSmallRank(const Type& x) /* Returns the smallest rank for which a CoxNbr holds the given element. It is assumed that x is one of the finite types A-I. */ { Rank l; unsigned long c; switch(x[0]) { case 'A': c = 1; for (l = 1; l < RANK_MAX; l++) { if (c > COXNBR_MAX/(l+1)) /* l is too big */ return l-1; c *= (l+1); } return l; case 'B': case 'C': c = 2; for (l = 2; l < RANK_MAX; l++) { if (c > COXNBR_MAX/2*l) /* l is too big */ return l-1; c *= 2*l; } return l; case 'D': c = 4; for (l = 3; l < RANK_MAX; l++) { if (c > COXNBR_MAX/2*l) /* l is too big */ return l-1; c *= 2*l; } return l; return l; case 'E': if (COXNBR_MAX < 2903040) return 6; else if (COXNBR_MAX < 696729600) return 7; else return 8; case 'F': return 4; case 'G': return 2; case 'H': return 4; case 'I': return 2; default: // unreachable return 0; }; } positivity_final/fcoxgroup.h0000600000175000017500000002053410012716273020022 0ustar duclouxducloux00000000000000/* This is fcoxgroup.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /**************************************************************************** This module defines the hierarchy of finite Coxeter groups; see coxgroup.h for the layout of the general hierarchy of Coxeter groups. As explained there, many of these classes are barely implemented. We also explained that only leaf classes in the hierarchy are concrete; in preparation for possible derivation of Finite*RankCoxGroup, we have shadowed them by the concrete classes F*RCoxGroup; the same holds for SmallCoxGroup. ****************************************************************************/ #ifndef FCOXGROUP_H /* guard against multiple inclusions */ #define FCOXGROUP_H #include "globals.h" #include "coxgroup.h" namespace fcoxgroup { using namespace globals; using namespace coxgroup; }; /******** type declarations *************************************************/ namespace fcoxgroup { class FiniteCoxGroup; class FiniteBigRankCoxGroup; class GeneralFBRCoxGroup; class FiniteMedRankCoxGroup; class GeneralFMRCoxGroup; class FiniteSmallRankCoxGroup; class GeneralFSRCoxGroup; class SmallCoxGroup; class GeneralSCoxGroup; typedef CoxNbr DenseArray; }; /******** function declarations *********************************************/ namespace fcoxgroup { bool isFiniteType(CoxGroup *W); Rank maxSmallRank(const Type& x); }; /******** type definitions **************************************************/ namespace fcoxgroup { class FiniteCoxGroup : public CoxGroup { protected: CoxArr d_longest_coxarr; CoxWord d_longest_coxword; Length d_maxlength; CoxSize d_order; Transducer *d_transducer; Partition d_lcell; Partition d_rcell; Partition d_lrcell; Partition d_luneqcell; Partition d_runeqcell; Partition d_lruneqcell; Partition d_ldescent; Partition d_rdescent; Partition d_ltau; Partition d_rtau; Partition d_lstring; Partition d_rstring; List d_duflo; public: /* constructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(FiniteCoxGroup));} FiniteCoxGroup(const Type& x, const Rank& l); virtual ~FiniteCoxGroup(); /* accessors */ bool isFullContext() const; const CoxArr& longest_coxarr() const; /* inlined */ const CoxWord& longest_coxword() const; /* inlined */ Length maxLength() const; /* inlined */ void modify(ParseInterface& P, const Token& tok) const; CoxSize order() const; /* inlined */ bool parseModifier(ParseInterface& P) const; const FiltrationTerm *transducer(const Rank& l = 0) const; /* inlined */ /* modifiers */ FiltrationTerm *transducer(const Rank& l = 0) {return d_transducer->transducer(l);} /* array operations */ const CoxArr& assign(CoxArr& a, const CoxArr& b) const; /* inlined */ virtual const CoxArr& inverseArr(CoxArr& a) const; Length length(const CoxArr& a) const; const CoxArr& powerArr(CoxArr& a, const Ulong& m) const; int prodArr(CoxArr& a, const CoxArr& b) const; LFlags rDescent(const CoxArr& a) const; const CoxWord& reducedArr(CoxWord& g, const CoxArr& a) const; const CoxArr& setZero(CoxArr& a) const; /* inlined */ /* mixed operations */ const CoxArr& assign(CoxArr& a, const CoxWord& g) const; int prodArr(CoxArr& a, Generator s) const; int prodArr(CoxArr& a, const CoxWord& g) const; // manipulators void fullContext(); /* inlined */ /* kazhdan-lusztig cells and realted partitions */ const Partition& lCell(); const Partition& lrCell(); const Partition& rCell(); const List& duflo(); const Partition& lUneqCell(); const Partition& lrUneqCell(); const Partition& rUneqCell(); const Partition& lDescent(); const Partition& rDescent(); const Partition& lString(); const Partition& rString(); const Partition& lTau(); const Partition& rTau(); }; class FiniteBigRankCoxGroup : public FiniteCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(FiniteBigRankCoxGroup));} FiniteBigRankCoxGroup(const Type& x, const Rank& l); virtual ~FiniteBigRankCoxGroup(); /* accessors */ kl::KLContext& kl() const; /* inlined */ }; class GeneralFBRCoxGroup : public FiniteBigRankCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralFBRCoxGroup));} GeneralFBRCoxGroup(const Type& x, const Rank& l); ~GeneralFBRCoxGroup(); }; class FiniteMedRankCoxGroup : public FiniteCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(FiniteMedRankCoxGroup));} FiniteMedRankCoxGroup(const Type& x, const Rank& l); virtual ~FiniteMedRankCoxGroup(); /* accessors */ kl::KLContext& kl() const; /* inlined */ }; class GeneralFMRCoxGroup : public FiniteMedRankCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralFMRCoxGroup));} GeneralFMRCoxGroup(const Type& x, const Rank& l); ~GeneralFMRCoxGroup(); }; class FiniteSmallRankCoxGroup : public FiniteMedRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(FiniteSmallRankCoxGroup));} FiniteSmallRankCoxGroup(const Type& x, const Rank& l); virtual ~FiniteSmallRankCoxGroup(); /* accessors */ kl::KLContext& kl() const; /* inlined */ }; class GeneralFSRCoxGroup : public FiniteSmallRankCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralFSRCoxGroup));} GeneralFSRCoxGroup(const Type& x, const Rank& l); ~GeneralFSRCoxGroup(); }; class SmallCoxGroup : public FiniteSmallRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(SmallCoxGroup));} SmallCoxGroup(const Type& x, const Rank& l); virtual ~SmallCoxGroup(); /* accessors */ const CoxArr& assign(CoxArr& a, const DenseArray& x) const; void assign(DenseArray& x, const CoxArr& a) const; bool parseDenseArray(ParseInterface& P) const; virtual bool parseGroupElement(ParseInterface& P) const; int prodD(CoxWord& g, const DenseArray& x) const; int prodD(DenseArray& x, const CoxWord& g) const; }; class GeneralSCoxGroup : public SmallCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralSCoxGroup));} GeneralSCoxGroup(const Type& x, const Rank& l); ~GeneralSCoxGroup(); }; }; /******** Inline implementations ******************************************/ namespace fcoxgroup { inline const CoxArr& FiniteCoxGroup::assign(CoxArr& a, const CoxArr& b) const {memmove(a,b,rank()*sizeof(ParNbr)); return a;} inline void FiniteCoxGroup::fullContext() {extendContext(d_longest_coxword);} inline const CoxArr& FiniteCoxGroup::longest_coxarr() const {return d_longest_coxarr;} inline const CoxWord& FiniteCoxGroup::longest_coxword() const {return d_longest_coxword;} inline Length FiniteCoxGroup::maxLength() const {return d_maxlength;} inline CoxSize FiniteCoxGroup::order() const {return d_order;} inline const CoxArr& FiniteCoxGroup::setZero(CoxArr& a) const {memset(a,0,rank()*sizeof(ParNbr)); return a;} inline const FiltrationTerm* FiniteCoxGroup::transducer(const Rank& l) const {return d_transducer->transducer(l);} }; #endif positivity_final/files.cpp0000600000175000017500000011037710011171251017436 0ustar duclouxducloux00000000000000/* This is files.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "files.h" #include "cells.h" #include "directories.h" #include "posets.h" #include "version.h" namespace files { using namespace directories; using namespace wgraph; } /**************************************************************************** This module contains code for the handling of output to files. It is our strong belief that the usefulness of a program depends greatly on the quality and flexibility of its output --- unfortunately there is no uniform measure of quality : a human reader will want a compact and well-formatted file, whereas a computer will want a file that is easy to parse, and a computer algebra system will want a file that is in its own format. At each point in time, the group has a component d_fileoutput, which is set to the current "style" of output (typically we envision pretty, terse, gap, tex and latex as desirable styles). This component contains the virtual function table corresponding to the desired output. The functions outputting to files are the following : - printClosure(file,h,p,I) : prints information about one schubert variety; the list of extremal pairs is contained in h; *****************************************************************************/ namespace { using namespace files; Ulong maxLength(const Homology& h); }; namespace { using namespace files; void makeVersionString(String& vstr, const String& str); void makeTypeString(String& tstr, const String& str, const CoxGraph& G); }; /**************************************************************************** Chapter I -- The OutputTraits class. This class holds all the little details which govern output of data to files. Although this may seem a lot of detail, it seems that not much less can be done is one is to automatically produce output suitable for direct input into programs such as TeX or GAP. Mostly, constructors are provided for the various output tags : - OutputTraits(Pretty); - OutputTraits(Terse); - OutputTraits(GAP); *****************************************************************************/ namespace files { OutputTraits::OutputTraits(const CoxGraph& G, const Interface& I, Pretty) :versionString(""), typeString(""), closureSeparator1("P_{x,y} for x extremal w.r.t. y:\n\n"), closureSeparator2(""), closureSeparator3("rational singular locus:\n\n"), closureSeparator4("rational singular stratification:\n\n"), closureSeparator5("betti numbers:\n\n"), closureSeparator6("IH betti numbers:\n\n"), eltList("context :\n\n"), singularLocus("singular locus :\n\n"), singularStratification("rational singular stratification :\n\n"), emptySingularLocus("rational singular locus is empty\n"), emptySingularStratification("rational singular stratification is empty\n"), bettiPrefix(""), bettiPostfix(""), bettiSeparator(""), bettiRankPrefix("h["), bettiRankPostfix("] = "), cellNumberPrefix(""), cellNumberPostfix(" : "), closureSizePrefix("size : "), closureSizePostfix(""), coatomPrefix("coatoms :\n\n"), coatomPostfix("\n"), coatomSeparator("\n"), compCountPrefix("components : "), compCountPostfix(""), dufloPrefix(""), dufloPostfix(""), dufloSeparator(":"), dufloListPrefix(""), dufloListPostfix(""), dufloListSeparator("\n"), dufloNumberPrefix(""), dufloNumberPostfix(" : "), eltNumberPrefix(""), eltNumberPostfix(":"), eltListPrefix(""), eltListPostfix(""), eltListSeparator("\n"), eltPrefix("y = "), eltPostfix(""), eltDataPrefix(""), eltDataPostfix("\n"), graphListPrefix(""), graphListPostfix(""), graphListSeparator("\n\n"), lDescentPrefix(" L:"), lDescentPostfix(""), rDescentPrefix(" R:"), rDescentPostfix(""), lengthPrefix(" length "), lengthPostfix(""), closeString("\n"), bettiHyphens("h"), lineSize(LINESIZE), polTraits(Pretty()), heckeTraits(I,Pretty()), addHeckeTraits(I,Pretty()), partitionTraits(Pretty()), wgraphTraits(Pretty()), posetTraits(Pretty()), printBettiRank(true), printCellNumber(true), printClosureSize(true), printCoatoms(true), printCompCount(true), printDufloNumber(true), printEltDescents(true), printElt(true), printEltData(true), printEltNumber(true), printLength(true), printType(false), printVersion(false), hasBettiPadding(true) { prefix[basisH] = ""; prefix[bettiH] = ""; prefix[closureH] = ""; prefix[dufloH] = ""; prefix[extremalsH] = ""; prefix[ihBettiH] = ""; prefix[lCOrderH] = ""; prefix[lCellsH] = ""; prefix[lCellWGraphsH] = ""; prefix[lWGraphH] = "graph :\n\n"; prefix[lrCOrderH] = ""; prefix[lrCellsH] = ""; prefix[lrCellWGraphsH] = ""; prefix[lrWGraphH] = "graph :\n\n"; prefix[rCOrderH] = ""; prefix[rCellsH] = ""; prefix[rCellWGraphsH] = ""; prefix[rWGraphH] = "graph :\n\n"; prefix[slocusH] = ""; prefix[sstratificationH] = ""; postfix[basisH] = "\n"; postfix[bettiH] = "\n"; postfix[closureH] = "\n"; postfix[dufloH] = "\n"; postfix[extremalsH] = "\n"; postfix[ihBettiH] = "\n"; postfix[lCOrderH] = "\n"; postfix[lCellsH] = "\n"; postfix[lCellWGraphsH] = "\n"; postfix[lWGraphH] = "\n"; postfix[lrCOrderH] = "\n"; postfix[lrCellsH] = "\n"; postfix[lrCellWGraphsH] = "\n"; postfix[lrWGraphH] = "\n"; postfix[rCOrderH] = "\n"; postfix[rCellsH] = "\n"; postfix[rCellWGraphsH] = "\n"; postfix[rWGraphH] = "\n"; postfix[slocusH] = "\n"; postfix[sstratificationH] = "\n"; hasHeader[bettiH] = false; hasHeader[basisH] = false; hasHeader[closureH] = false; hasHeader[dufloH] = false; hasHeader[extremalsH] = false; hasHeader[ihBettiH] = false; hasHeader[lCOrderH] = false; hasHeader[lCellsH] = false; hasHeader[lCellWGraphsH] = false; hasHeader[lWGraphH] = false; hasHeader[lrCOrderH] = false; hasHeader[lrCellsH] = false; hasHeader[lrCellWGraphsH] = false; hasHeader[lrWGraphH] = false; hasHeader[rCOrderH] = false; hasHeader[rCellsH] = false; hasHeader[rCellWGraphsH] = false; hasHeader[rWGraphH] = false; hasHeader[slocusH] = false; hasHeader[sstratificationH] = false; } OutputTraits::OutputTraits(const CoxGraph& G, const Interface& I, Terse) :versionString(""), typeString(""), closureSeparator1("# extremal pairs\n"), closureSeparator2(""), closureSeparator3("# rational singular locus\n"), closureSeparator4("# rational singular stratification\n"), closureSeparator5("# betti numbers\n"), closureSeparator6("# IH betti numbers\n"), eltList("# context enumeration\n"), singularLocus("# rational singular locus\n"), singularStratification("# rational singular stratification\n"), emptySingularLocus("# rational singular locus is empty"), emptySingularStratification("# rational singular stratification is empty"), bettiPrefix(""), bettiPostfix(""), bettiSeparator(","), dufloPrefix(""), dufloPostfix(""), dufloSeparator(":"), dufloListPrefix(""), dufloListPostfix(""), dufloListSeparator("\n"), eltListPrefix(""), eltListPostfix(""), eltListSeparator("\n"), eltPrefix(""), eltPostfix(""), eltDataPrefix("# the element y\n"), eltDataPostfix(""), graphListPrefix(""), graphListPostfix(""), graphListSeparator("\n#\n"), closeString(""), polTraits(Terse()), heckeTraits(I,Terse()), addHeckeTraits(I,Terse()), partitionTraits(Terse()), wgraphTraits(Terse()), posetTraits(Terse()), printBettiRank(false), printCellNumber(false), printClosureSize(false), printCoatoms(false), printCompCount(false), printDufloNumber(false), printEltDescents(false), printElt(true), printEltData(true), printEltNumber(false), printLength(false), printType(true), printVersion(true), hasBettiPadding(false) { prefix[basisH] = ""; prefix[bettiH] = ""; prefix[closureH] = ""; prefix[dufloH] = ""; prefix[extremalsH] = ""; prefix[ihBettiH] = ""; prefix[lCOrderH] = ""; prefix[lCellsH] = ""; prefix[lCellWGraphsH] = ""; prefix[lWGraphH] = "# graph\n"; prefix[lrCOrderH] = ""; prefix[lrCellsH] = ""; prefix[lrCellWGraphsH] = ""; prefix[lrWGraphH] = "# graph\n"; prefix[rCOrderH] = ""; prefix[rCellsH] = ""; prefix[rCellWGraphsH] = ""; prefix[rWGraphH] = "# graph\n"; prefix[slocusH] = ""; prefix[sstratificationH] = ""; postfix[basisH] = ""; postfix[bettiH] = ""; postfix[closureH] = ""; postfix[dufloH] = ""; postfix[extremalsH] = ""; postfix[ihBettiH] = ""; postfix[lCOrderH] = ""; postfix[lCellsH] = ""; postfix[lCellWGraphsH] = ""; postfix[lWGraphH] = ""; postfix[lrCOrderH] = ""; postfix[lrCellsH] = ""; postfix[lrCellWGraphsH] = ""; postfix[lrWGraphH] = ""; postfix[rCOrderH] = ""; postfix[rCellsH] = ""; postfix[rCellWGraphsH] = ""; postfix[rWGraphH] = ""; postfix[slocusH] = ""; postfix[sstratificationH] = ""; header[basisH] = "terse_basis"; header[closureH] = "terse_closure"; header[dufloH] = "terse_duflo"; header[extremalsH] = "terse_extremals"; header[lCOrderH] = "terse_lcorder"; header[lCellsH] = "terse_lcells"; header[lCellWGraphsH] = "terse_lcellwgraphs"; header[lWGraphH] = "terse_lwgraph"; header[lrCOrderH] = "terse_lrcorder"; header[lrCellsH] = "terse_lrcells"; header[lrCellWGraphsH] = "terse_lrcellwgraphs"; header[lrWGraphH] = "terse_lrwgraph"; header[rCOrderH] = "terse_rcorder"; header[rCellsH] = "terse_rcells"; header[rCellWGraphsH] = "terse_rcellwgraphs"; header[rWGraphH] = "terse_rwgraph"; header[slocusH] = "terse_slocus"; header[sstratificationH] = "terse_sstratification"; hasHeader[bettiH] = false; hasHeader[basisH] = true; hasHeader[closureH] = true; hasHeader[dufloH] = true; hasHeader[extremalsH] = true; hasHeader[ihBettiH] = false; hasHeader[lCOrderH] = true; hasHeader[lCellsH] = true; hasHeader[lCellWGraphsH] = true; hasHeader[lWGraphH] = true; hasHeader[lrCOrderH] = true; hasHeader[lrCellsH] = true; hasHeader[lrCellWGraphsH] = true; hasHeader[lrWGraphH] = true; hasHeader[rCOrderH] = true; hasHeader[rCellsH] = true; hasHeader[rCellWGraphsH] = true; hasHeader[rWGraphH] = true; hasHeader[slocusH] = true; hasHeader[sstratificationH] = true; makeVersionString(versionString,"#"); makeTypeString(typeString,"#",G); } OutputTraits::OutputTraits(const CoxGraph& G, const Interface& I, GAP) :versionString(""), typeString(""), closureSeparator1(""), closureSeparator2(""), closureSeparator3(""), closureSeparator4(""), closureSeparator5(""), closureSeparator6(""), eltList("coxeter_contextEnumeration:="), singularLocus("coxeter_slocus:="), singularStratification("coxeter_sstratification:="), emptySingularLocus("coxeter_slocus:=[];"), emptySingularStratification("coxeter_sstratification:=[];"), bettiPrefix("["), bettiPostfix("]"), bettiSeparator(","), dufloPrefix("["), dufloPostfix("]"), dufloSeparator(","), dufloListPrefix("[\n"), dufloListPostfix("]"), dufloListSeparator(",\n"), eltListPrefix("[\n"), eltListPostfix("]"), eltListSeparator(",\n"), eltPrefix("coxeter_currentElement:="), eltPostfix(";"), eltDataPrefix(""), eltDataPostfix(""), graphListPrefix("[\n"), graphListPostfix("]"), graphListSeparator(",\n"), closeString(";"), polTraits(GAP()), heckeTraits(I,GAP()), addHeckeTraits(I,GAP()), partitionTraits(GAP()), wgraphTraits(GAP()), posetTraits(GAP()), printBettiRank(false), printCellNumber(false), printClosureSize(false), printCoatoms(false), printCompCount(false), printDufloNumber(false), printEltDescents(false), printElt(true), printEltData(true), printEltNumber(false), printLength(false), printType(true), printVersion(true), hasBettiPadding(false) { prefix[basisH] = "coxeter_cbasis:="; prefix[bettiH] = "coxeter_betti:="; prefix[closureH] = ""; prefix[dufloH] = "coxeter_duflo:="; prefix[extremalsH] = "coxeter_criticalPairs:="; prefix[ihBettiH] = "coxeter_ihbetti:="; prefix[lCOrderH] = "coxeter_lcorder:="; prefix[lCellsH] = "coxeter_lcells:="; prefix[lCellWGraphsH] = "coxeter_lcwgraphs:="; prefix[lWGraphH] = "coxeter_lwgraph:="; prefix[lrCOrderH] = "coxeter_lrcorder:="; prefix[lrCellsH] = "coxeter_lrcells:="; prefix[lrCellWGraphsH] = "coxeter_lrcwgraphs:="; prefix[lrWGraphH] = "coxeter_lrwgraph:="; prefix[rCOrderH] = "coxeter_rcorder:="; prefix[rCellsH] = "coxeter_rcells:="; prefix[rCellWGraphsH] = "coxeter_rcwgraphs:="; prefix[rWGraphH] = "coxeter_rwgraph:="; prefix[slocusH] = "coxeter_slocus:="; prefix[sstratificationH] = "coxeter_sstratification:="; postfix[basisH] = ";"; postfix[bettiH] = ";"; postfix[closureH] = ""; postfix[dufloH] = ";"; postfix[extremalsH] = ";"; postfix[ihBettiH] = ";"; postfix[lCOrderH] = ";"; postfix[lCellsH] = ";"; postfix[lCellWGraphsH] = ";"; postfix[lWGraphH] = ";"; postfix[lrCOrderH] = ";"; postfix[lrCellsH] = ";"; postfix[lrCellWGraphsH] = ";"; postfix[lrWGraphH] = ";"; postfix[rCOrderH] = ";"; postfix[rCellsH] = ";"; postfix[rCellWGraphsH] = ";"; postfix[rWGraphH] = ";"; postfix[slocusH] = ";"; postfix[sstratificationH] = ";"; header[basisH] = "GAPbasis"; header[closureH] = "GAPclosure"; header[dufloH] = "GAPduflo"; header[extremalsH] = "GAPextremals"; header[lCOrderH] = "GAPlcorder"; header[lCellsH] = "GAPlcells"; header[lCellWGraphsH] = "GAPlcellwgraphs"; header[lWGraphH] = "GAPlwgraph"; header[lrCOrderH] = "GAPlrcorder"; header[lrCellsH] = "GAPlrcells"; header[lrCellWGraphsH] = "GAPlrcellwgraphs"; header[lrWGraphH] = "GAPlrwgraph"; header[rCOrderH] = "GAPrcorder"; header[rCellsH] = "GAPrcells"; header[rCellWGraphsH] = "GAPrcellwgraphs"; header[rWGraphH] = "GAPrwgraph"; header[slocusH] = "GAPslocus"; header[sstratificationH] = "GAPsstratification"; hasHeader[bettiH] = false; hasHeader[basisH] = true; hasHeader[closureH] = true; hasHeader[dufloH] = true; hasHeader[extremalsH] = true; hasHeader[ihBettiH] = false; hasHeader[lCOrderH] = true; hasHeader[lCellsH] = true; hasHeader[lCellWGraphsH] = true; hasHeader[lWGraphH] = true; hasHeader[lrCOrderH] = true; hasHeader[lrCellsH] = true; hasHeader[lrCellWGraphsH] = true; hasHeader[lrWGraphH] = true; hasHeader[rCOrderH] = true; hasHeader[rCellsH] = true; hasHeader[rCellWGraphsH] = true; hasHeader[rWGraphH] = true; hasHeader[slocusH] = true; hasHeader[sstratificationH] = true; makeVersionString(versionString,"##"); makeTypeString(typeString,"##",G); } OutputTraits::~OutputTraits() {} } /**************************************************************************** Chapter II -- The HeckeTraits class. This class holds the part of the OutputTraits which is relevant for output of Hecke algebra elements. Mostly, constructors are provided for the various output tags : - HeckeTraits(Pretty); - HeckeTraits(Terse); - HeckeTraits(GAP); Also for the derived class AddHeckeTraits, which is used for printing out Hecke algebra elements in vector form. - AddHeckeTraits(Pretty); - AddHeckeTraits(Terse); - AddHeckeTraits(GAP); *****************************************************************************/ namespace files { HeckeTraits::HeckeTraits(const Interface& I, Pretty) :prefix(""), postfix(""), evenSeparator(""), oddSeparator("\n"), monomialPrefix(""), monomialPostfix(""), monomialSeparator(" : "), muMark(" *"), hyphens("+"), lineSize(LINESIZE), indent(4), evenWidth(HALFLINESIZE), oddWidth(0), padChar(' '), doShift(false), reversePrint(false), twoSided(true) {} HeckeTraits::HeckeTraits(const Interface& I, Terse) :prefix(""), postfix(""), evenSeparator(""), oddSeparator("\n"), monomialPrefix(""), monomialPostfix(""), monomialSeparator(":"), muMark(""), lineSize(0), evenWidth(0), oddWidth(0), padChar(' '), doShift(false), reversePrint(false), twoSided(false) {} HeckeTraits::HeckeTraits(const Interface& I, GAP) :prefix("[\n"), postfix("]"), evenSeparator(""), oddSeparator(",\n"), monomialPrefix("["), monomialPostfix("]"), monomialSeparator(","), muMark(""), lineSize(0), evenWidth(0), oddWidth(0), doShift(false), reversePrint(false), twoSided(false) {} HeckeTraits::~HeckeTraits() {} AddHeckeTraits::AddHeckeTraits(const Interface& I, Pretty) :HeckeTraits(I,Pretty()) { eltTraits = new GroupEltInterface(I.outInterface()); } AddHeckeTraits::AddHeckeTraits(const Interface& I, Terse) :HeckeTraits(I,Terse()) { eltTraits = new GroupEltInterface(I.outInterface()); doShift = true; } AddHeckeTraits::AddHeckeTraits(const Interface& I, GAP) :HeckeTraits(I,GAP()) { eltTraits = new GroupEltInterface(I.outInterface()); prefix = ""; postfix = ""; oddSeparator = "+"; monomialPrefix = "("; monomialPostfix = ")"; monomialSeparator = ")*t("; reversePrint = true; doShift = true; eltTraits->prefix = ""; eltTraits->postfix = ""; } AddHeckeTraits::~AddHeckeTraits() { delete eltTraits; } }; /**************************************************************************** Chapter III -- The PartitionTraits class. This class holds the part of the OutputTraits which is relevant for output of partitions. Mostly, constructors are provided for the various output tags : - PartitionTraits(Pretty); - PartitionTraits(Terse); - PartitionTraits(GAP); *****************************************************************************/ namespace files { PartitionTraits::PartitionTraits(Pretty) :prefix(""), postfix(""), separator("\n"), classPrefix("{"), classPostfix("}"), classSeparator(","), classNumberPrefix(""), classNumberPostfix(" : "), printClassNumber(true) {} PartitionTraits::PartitionTraits(Terse) :prefix(""), postfix(""), separator("\n"), classPrefix(""), classPostfix(""), classSeparator(","), classNumberPrefix(""), classNumberPostfix(""), printClassNumber(false) {} PartitionTraits::PartitionTraits(GAP) :prefix("[\n"), postfix("]"), separator(",\n"), classPrefix("["), classPostfix("]"), classSeparator(","), classNumberPrefix(""), classNumberPostfix(""), printClassNumber(false) {} PartitionTraits::~PartitionTraits() {} }; /**************************************************************************** Chapter IV -- The PolynomialTraits class. This class holds the part of the OutputTraits which is relevant for output of polynomials Mostly, constructors are provided for the various output tags : - PolynomialTraits(Pretty); - PolynomialTraits(Terse); - PolynomialTraits(GAP); *****************************************************************************/ namespace files { PolynomialTraits::PolynomialTraits(Pretty) :prefix(""), postfix(""), indeterminate("q"), sqrtIndeterminate("u"), posSeparator("+"), negSeparator(""), product(""), exponent("^"), expPrefix(""), expPostfix(""), zeroPol("0"), one(""), negOne("-"), modifierPrefix(""), modifierPostfix(""), modifierSeparator(""), printExponent(true), printModifier(false) {} PolynomialTraits::PolynomialTraits(Terse) :prefix("["), postfix("]"), indeterminate(""), sqrtIndeterminate(""), posSeparator(","), negSeparator(","), product(""), exponent(""), expPrefix(""), expPostfix(""), zeroPol("[]"), one("1"), negOne("-1"), modifierPrefix("("), modifierPostfix(")"), modifierSeparator(","), printExponent(false), printModifier(true) {} PolynomialTraits::PolynomialTraits(GAP) :prefix(""), postfix(""), indeterminate("q"), sqrtIndeterminate("u"), posSeparator("+"), negSeparator(""), product(""), exponent("^"), expPrefix(""), expPostfix(""), zeroPol("0"), one(""), negOne("-"), modifierPrefix(""), modifierPostfix(""), modifierSeparator(""), printExponent(true), printModifier(false) {} PolynomialTraits::~PolynomialTraits() {} }; /**************************************************************************** Chapter V --- The PosetTraits class. This class holds the part of the OutputTraits which is relevant for the printout of abstract posets. Mostly, constructors are provided for the various tags : - PosetTraits(Pretty); - PosetTraits(Terse); - PosetTraits(GAP); *****************************************************************************/ namespace files { PosetTraits::PosetTraits(Pretty) :prefix(""), postfix(""), separator("\n"), edgePrefix(""), edgePostfix(""), edgeSeparator(","), nodePrefix(""), nodePostfix(" : "), nodeShift(0), printNode(true) {} PosetTraits::PosetTraits(Terse) :prefix(""), postfix(""), separator("\n"), edgePrefix(""), edgePostfix(""), edgeSeparator(","), nodePrefix(""), nodePostfix(""), nodeShift(0), printNode(false) {} PosetTraits::PosetTraits(GAP) :prefix("[\n"), postfix("]"), separator(",\n"), edgePrefix("["), edgePostfix("]"), edgeSeparator(","), nodePrefix(""), nodePostfix(""), nodeShift(1), printNode(false) {} PosetTraits::~PosetTraits() {} }; /**************************************************************************** Chapter VI -- The WgraphTraits class. This class holds the part of the OutputTraits which is relevant for output of W-graphs. Mostly, constructors are provided for the various output tags : - WgraphTraits(Pretty); - WgraphTraits(Terse); - WgraphTraits(GAP); *****************************************************************************/ namespace files { WgraphTraits::WgraphTraits(Pretty) :prefix(""), postfix(""), separator("\n"), edgeListPrefix("{"), edgeListPostfix("}"), edgeListSeparator(","), edgePrefix("("), edgePostfix(")"), edgeSeparator(","), nodePrefix(""), nodePostfix(""), nodeSeparator(":"), nodeNumberPrefix(""), nodeNumberPostfix(":"), nodeShift(0), hasPadding(true), printNodeNumber(true) {} WgraphTraits::WgraphTraits(Terse) :prefix(""), postfix(""), separator("\n"), edgeListPrefix("{"), edgeListPostfix("}"), edgeListSeparator(","), edgePrefix("("), edgePostfix(")"), edgeSeparator(","), nodePrefix(""), nodePostfix(""), nodeSeparator(":"), nodeShift(0), padSize(0), hasPadding(false), printNodeNumber(false) {} WgraphTraits::WgraphTraits(GAP) :prefix("[\n"), postfix("]"), separator(",\n"), edgeListPrefix("["), edgeListPostfix("]"), edgeListSeparator(","), edgePrefix("["), edgePostfix("]"), edgeSeparator(","), nodePrefix("["), nodePostfix("]"), nodeSeparator(","), nodeShift(0), hasPadding(false), printNodeNumber(false) {} WgraphTraits::~WgraphTraits() {} } /**************************************************************************** Chapter VII --- Output functions. This section contains the definition of the output functions declared in files.h, and which are not templates : - appendHomology(str,h,traits) : appends a homology vector; - printBetti(file,y,p,traits) : prints the betti numbers of [e,y]; - printCellOrder(file,X,p,order,traits) : prints the set of cells in X as an abstract poset; - printCoatoms(file,y,p,traits) : prints data about the element y; - printDescents(file,df,f,traits) : prints df as a descent set; - printEltData(file,y,p,traits) : prints data about the element y; - printHeader(file,header,traits) : prints the header; - printHomology(file,h,traits) : prints a homology vector; - printPartition(file,pi,p,order,traits); - printWGraph(file,X,f,traits) : prints a W-graph; *****************************************************************************/ namespace files { void appendHomology(String& str, const Homology& h, OutputTraits& traits) /* Appends the homology vector to str. */ { Ulong initLength = str.length(); Ulong maxWidth = maxLength(h); // maximum width of output io::append(str,traits.bettiPrefix); for (Ulong j = 0; j < h.size(); ++j) { if (traits.printBettiRank) { io::append(str,traits.bettiRankPrefix); io::append(str,j); io::append(str,traits.bettiRankPostfix); } io::append(str,static_cast(h[j])); if (traits.hasBettiPadding) io::pad(str,(j+1)*(maxWidth+1)+initLength); if (j+1 < h.size()) // there is more to come io::append(str,traits.bettiSeparator); } io::append(str,traits.bettiPostfix); return; } void printBetti(FILE* file, const CoxNbr& y, const SchubertContext& p, OutputTraits& traits) { Homology h(0); betti(h,y,p); io::print(file,traits.prefix[bettiH]); printHomology(file,h,traits); io::print(file,traits.postfix[bettiH]); fprintf(file,"\n"); return; } void printCellOrder(FILE* file, const OrientedGraph& X, const SchubertContext& p, const Interface& I, PosetTraits& traits) /* This function prints out the poset of cells defined by the graph X. The interface parameter is needed to determine the shortLex ordering of the elements. */ { OrientedGraph P(0); Partition pi(0); X.cells(pi,&P); posets::Poset Q(P); OrientedGraph H(0); Q.hasseDiagram(H); List > lc(0); writeClasses(lc,pi); schubert::NFCompare nfc(p,I.order()); Permutation a(0); sortLists(lc,nfc,a); a.inverse(); H.permute(a); io::print(file,traits.prefix); for (Ulong j = 0; j < pi.classCount(); ++j) { if (traits.printNode) { io::print(file,traits.nodePrefix); fprintf(file,"%lu",j+traits.nodeShift); io::print(file,traits.nodePostfix); } const EdgeList& e = H.edge(j); io::print(file,traits.edgePrefix); for (Ulong i = 0; i < e.size(); ++i) { fprintf(file,"%lu",e[i]+traits.nodeShift); if (i+1 < e.size()) /* there is more to come */ io::print(file,traits.edgeSeparator); } io::print(file,traits.edgePostfix); if (j+1 < pi.classCount()) // there is more to come io::print(file,traits.separator); } io::print(file,traits.postfix); return; } void printCoatoms(FILE* file, const CoxNbr& y, const SchubertContext& p, const Interface& I, OutputTraits& traits) /* Prints out the coatoms of y. */ { const CoatomList& c = p.hasse(y); io::print(file,traits.coatomPrefix); for (Ulong j = 0; j < c.size(); ++j) { p.print(file,c[j],I); if (j+1 < c.size()) // there is more to come io::print(file,traits.coatomSeparator); } io::print(file,traits.coatomPostfix); return; } void printDescents(FILE* file, const LFlags& df, const LFlags& f, const Interface& I, WgraphTraits& traits) { if (!(f&1)) { // left descents print(file,df,I); } else if ((f >> I.rank()) == 0) { // right descents print(file,df,I); } else { // two-sided descents printTwosided(file,df,I); } return; } void printEltData(FILE* file, const CoxNbr& y, const SchubertContext& p, const Interface& I, OutputTraits& traits) /* This function prints out some data about the element y : - normal form; - left and right descent sets; - length; */ { io::print(file,traits.eltDataPrefix); if (traits.printElt) { io::print(file,traits.eltPrefix); p.print(file,y,I); io::print(file,traits.eltPostfix); } if (traits.printEltDescents) { io::print(file,traits.lDescentPrefix); print(file,p.ldescent(y),I); io::print(file,traits.lDescentPostfix); io::print(file,traits.rDescentPrefix); print(file,p.rdescent(y),I); io::print(file,traits.rDescentPostfix); } if (traits.printLength) { io::print(file,traits.lengthPrefix); fprintf(file,"%lu",static_cast(p.length(y))); io::print(file,traits.lengthPostfix); } io::print(file,traits.eltDataPostfix); return; } void printHeader(FILE* file, const Header& header, OutputTraits& traits) /* Prints the header part of the file. It has already been checked if the header has to be printed. */ { using namespace directories; // preliminaries if (traits.printVersion) io::print(file,traits.versionString); if (traits.printType) io::print(file,traits.typeString); if (traits.hasHeader[header]) printFile(file,traits.header[header].ptr(),HEADER_DIR); return; } void printHomology(FILE* file, const Homology& h, OutputTraits& traits) { String buf(0); appendHomology(buf,h,traits); if (traits.lineSize) foldLine(file,buf,traits.lineSize,0,traits.bettiHyphens.ptr()); else io::print(file,buf); if (traits.printClosureSize) { fprintf(file,"\n\n"); Ulong size = 0; for (Ulong j = 0; j < h.size(); ++j) size += h[j]; io::print(file,traits.closureSizePrefix); fprintf(file,"%lu",size); io::print(file,traits.closureSizePostfix); } return; } void printPartition(FILE* file, const Partition& pi, const SchubertContext& p, const Interface& I, PartitionTraits& traits) /* Prints out the classes of the partition, according to the given traits. */ { List > lc(0); writeClasses(lc,pi); schubert::NFCompare nfc(p,I.order()); Permutation a(0); sortLists(lc,nfc,a); int d = digits(lc.size()-1,10); io::print(file,traits.prefix); for (Ulong j = 0; j < lc.size(); ++j) { List l = lc[a[j]]; if (traits.printClassNumber) { io::print(file,traits.classNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.classNumberPostfix); } io::print(file,traits.classPrefix); for (Ulong i = 0; i < l.size(); ++i) { p.print(file,l[i],I); if (i+1 < l.size()) /* there is more to come */ io::print(file,traits.classSeparator); } io::print(file,traits.classPostfix); if (j+1 < lc.size()) // there is more to come io::print(file,traits.separator); } io::print(file,traits.postfix); return; } void printWGraph(FILE* file, const WGraph& X, const LFlags& f, const Interface& I, WgraphTraits& traits) /* This function prints out a W-graph. We represent a W-graph as a list of pairs [descent set,edge-list]. The edge-list itself is a set of pairs [dest,mu], where dest is the end-point of the edge, and mu is the mu-coefficient. */ { int d = digits(X.size()-1,10); io::print(file,traits.prefix); for (Ulong j = 0; j < X.size(); ++j) { if (traits.printNodeNumber) { io::print(file,traits.nodeNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.nodeNumberPostfix); } io::print(file,traits.nodePrefix); printDescents(file,X.descent(j),f,I,traits); io::print(file,traits.nodeSeparator); const CoeffList& mu = X.coeffList(j); const EdgeList& e = X.edge(j); io::print(file,traits.edgeListPrefix); for (Ulong i = 0; i < e.size(); ++i) { io::print(file,traits.edgePrefix); fprintf(file,"%lu",static_cast(e[i])); io::print(file,traits.edgeSeparator); fprintf(file,"%ld",static_cast(mu[i])); io::print(file,traits.edgePostfix); if (i+1 < e.size()) // there is more to come io::print(file,traits.edgeListSeparator); } io::print(file,traits.edgeListPostfix); io::print(file,traits.nodePostfix); if (j+1 < X.size()) { // there is more to come io::print(file,traits.separator); if (traits.hasPadding) fprintf(file,"%*s",traits.padSize,""); } } io::print(file,traits.postfix); return; } }; /**************************************************************************** Chapter VIII --- Helper functions This section defines some helper functions declared in files.h: - appendModifier(str,d,m,traits) : does the printing of the modifier; - appendSeparator(str,n,traits) : does the printing of the separator; - minReps(min,pi,c) : extracts minimal representatives of the classes in pi; - printModifier(str,d,m,traits) : does the printing of the modifier; - printSeparator(file,n,traits) : does the printing of the separator; - setTwoSided(traits,f) : sets *traits.twoSided to f; - sortLists(lc,nfc,a) : sorts the various lists in lc; - writeClasses(lc,pi) : writes out the classes of pi in lc; and some others private to the present module: - makeVersionString(vstr,str) : makes the version string with str as prefix; - makeTypeString(tstr,str) : makes the type string with str as prefix; *****************************************************************************/ namespace files { void appendModifier(String& str, const Ulong& d, const long& m, PolynomialTraits& traits) /* Appends the polynomial modifier to the string. */ { io::append(str,traits.modifierPrefix); io::append(str,static_cast(d)); io::append(str,traits.modifierSeparator); io::append(str,static_cast(m)); io::append(str,traits.modifierPostfix); return; } void appendSeparator(String& str, const Ulong& n, HeckeTraits& traits) { if (traits.twoSided) { // need to look at parity of n if (n%2) io::append(str,traits.oddSeparator); else io::append(str,traits.evenSeparator); } else io::append(str,traits.oddSeparator); return; } void minReps(List& min, const Partition& pi, schubert::NFCompare& c) /* Extracts the minimal representative from each class in pi, for the comparison functor c, and writes it in min, in the order of the partition numbers. */ { for (PartitionIterator i(pi); i; ++i) { CoxNbr x = schubert::min(i(),c); min.append(x); } return; } void pad(String& str, const Ulong& n, HeckeTraits& traits) /* Adds padding to the string, to make its length at least equal to traits.even(odd)Width, according to the parity of n. If the width is zero, no padding is added. */ { if (!traits.twoSided) return; if (n%2 && traits.oddWidth) { Ulong m = str.length(); if (m < traits.oddWidth) { // odd padding for (Ulong j = m; j < traits.oddWidth; ++j) io::append(str,traits.padChar); } } if (!(n%2) && traits.evenWidth) { Ulong m = str.length(); if (m < traits.evenWidth) { // odd padding for (Ulong j = m; j < traits.evenWidth; ++j) io::append(str,traits.padChar); } } return; } void printModifier(FILE* file, const Ulong& d, const long& m, PolynomialTraits& traits) /* Prints the modifier parameters (d,m). */ { io::print(file,traits.modifierPrefix); fprintf(file,"%lu",d); io::print(file,traits.modifierSeparator); fprintf(file,"%ld",m); io::print(file,traits.modifierPostfix); return; } void printSeparator(FILE* file, const Ulong& n, HeckeTraits& traits) { if (traits.twoSided) { // need to look at parity of n if (n%2) io::print(file,traits.oddSeparator); else io::print(file,traits.evenSeparator); } else io::print(file,traits.oddSeparator); return; } void sortLists(List >& lc, schubert::NFCompare& nfc, Permutation& a) /* This function sorts the various rows in lc, and puts in a the permutation which sorts ld according to the first term in each row. */ { List lfirst(0); lfirst.setSize(lc.size()); for (Ulong j = 0; j < lc.size(); ++j) { lc[j].sort(nfc); lfirst[j] = lc[j][0]; } sortI(lfirst,nfc,a); return; } void writeClasses(List >& lc, const Partition& pi) /* This function writes out in lc the various classes of the partition pi. */ { lc.setSize(pi.classCount()); Ulong j = 0; for (PartitionIterator i(pi); i; ++i) { new(&lc[j]) List(i().begin(),i().end()); ++j; } return; } }; namespace { void makeVersionString(String& vstr, const String& str) { append(vstr,str); append(vstr,"\n"); append(vstr,str); append(vstr," This file has been created by "); append(vstr,version::NAME); append(vstr," version "); append(vstr,version::VERSION); append(vstr,"\n"); return; } void makeTypeString(String& tstr, const String& str, const CoxGraph& G) { append(tstr,str); append(tstr,"\n"); append(tstr,str); append(tstr," Group type is "); append(tstr,G.type().name()); append(tstr,G.rank()); append(tstr,"\n"); return; } }; namespace { Ulong maxLength(const Homology& h) /* Returns the maximal length of an entry in h. */ { static String buf(0); Ulong maxl = 0; for (Ulong j = 0; j < h.size(); ++j) { reset(buf); append(buf,"h["); append(buf,j); append(buf,"] = "); append(buf,h[j]); if (maxl < buf.size()) maxl = buf.size(); } return maxl; } }; positivity_final/coxeter_matrices/0000700000175000017500000000000007763766725021221 5ustar duclouxducloux00000000000000positivity_final/coxeter_matrices/53350000600000175000017500000000006207576410316021523 0ustar duclouxducloux000000000000001 5 2 2 2 5 1 3 2 2 2 3 1 3 2 2 2 3 1 5 2 2 2 5 1 positivity_final/coxeter_matrices/a10000600000175000017500000000001007576410316021416 0ustar duclouxducloux000000000000001 0 0 1 positivity_final/coxeter_matrices/a20000600000175000017500000000002207576410316021422 0ustar duclouxducloux000000000000001 3 3 3 1 3 3 3 1 positivity_final/coxeter_matrices/a30000600000175000017500000000004007576410316021423 0ustar duclouxducloux000000000000001 3 2 3 3 1 3 2 2 3 1 3 3 2 3 1 positivity_final/coxeter_matrices/a40000600000175000017500000000006207576410316021430 0ustar duclouxducloux000000000000001 3 2 2 3 3 1 3 2 2 2 3 1 3 2 2 2 3 1 3 3 2 2 3 1 positivity_final/coxeter_matrices/a50000600000175000017500000000011007576410316021423 0ustar duclouxducloux000000000000001 3 2 2 2 3 3 1 3 2 2 2 2 3 1 3 2 2 2 2 3 1 3 2 2 2 2 3 1 3 3 2 2 2 3 1 positivity_final/coxeter_matrices/b20000600000175000017500000000002107576410316021422 0ustar duclouxducloux000000000000001 4 2 4 1 4 2 4 1positivity_final/coxeter_matrices/b30000600000175000017500000000003707576410316021432 0ustar duclouxducloux000000000000001 4 2 2 4 1 3 3 2 3 1 2 2 3 2 1positivity_final/coxeter_matrices/b40000600000175000017500000000006207576410316021431 0ustar duclouxducloux000000000000001 4 2 2 2 4 1 3 2 2 2 3 1 3 3 2 2 3 1 2 2 2 3 2 1 positivity_final/coxeter_matrices/b50000600000175000017500000000011007576410316021424 0ustar duclouxducloux000000000000001 4 2 2 2 2 4 1 3 2 2 2 2 3 1 3 2 2 2 2 3 1 3 3 2 2 2 3 1 2 2 2 2 3 2 1 positivity_final/coxeter_matrices/c30000600000175000017500000000004007576410316021425 0ustar duclouxducloux000000000000001 4 2 2 4 1 3 2 2 3 1 4 2 2 4 1 positivity_final/coxeter_matrices/c40000600000175000017500000000006307576410316021433 0ustar duclouxducloux000000000000001 4 2 2 2 4 1 3 2 2 2 3 1 3 2 2 2 3 1 4 2 2 2 4 1 positivity_final/coxeter_matrices/c50000600000175000017500000000011007576410316021425 0ustar duclouxducloux000000000000001 4 2 2 2 2 4 1 3 2 2 2 2 3 1 3 2 2 2 2 3 1 3 2 2 2 2 3 1 4 2 2 2 2 4 1 positivity_final/coxeter_matrices/d40000600000175000017500000000006207576410316021433 0ustar duclouxducloux000000000000001 2 3 2 2 2 1 3 2 2 3 3 1 3 3 2 2 3 1 2 2 2 3 2 1 positivity_final/coxeter_matrices/d50000600000175000017500000000011007576410316021426 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 1 3 2 2 2 3 3 1 3 2 2 2 2 3 1 3 3 2 2 2 3 1 2 2 2 2 3 2 1 positivity_final/coxeter_matrices/e60000600000175000017500000000014207576410316021435 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 1 2 3 2 2 3 3 2 1 3 2 2 2 2 3 3 1 3 2 2 2 2 2 3 1 3 2 2 2 2 2 3 1 2 2 3 2 2 2 2 1 positivity_final/coxeter_matrices/e70000600000175000017500000000020007576410316021431 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 3 2 1 2 3 2 2 2 2 3 2 1 3 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 3 1 2 3 2 2 2 2 2 2 1 positivity_final/coxeter_matrices/e80000600000175000017500000000024207576410316021440 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/f40000600000175000017500000000006207576410316021435 0ustar duclouxducloux000000000000001 3 2 2 2 3 1 4 2 2 2 4 1 3 2 2 2 3 1 3 2 2 2 3 1 positivity_final/coxeter_matrices/g20000600000175000017500000000002207576410316021430 0ustar duclouxducloux000000000000001 6 2 6 1 3 2 3 1 positivity_final/coxeter_matrices/howlett2_50000600000175000017500000000171007576410316023121 0ustar duclouxducloux000000000000001 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 5 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 5 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett30000600000175000017500000000171007576410316022676 0ustar duclouxducloux000000000000001 5 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 5 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett10000600000175000017500000000220007576410316022667 0ustar duclouxducloux000000000000001 4 3 6 6 4 2 6 5 6 4 4 5 3 3 5 3 6 5 4 2 3 4 6 4 1 5 4 4 2 6 3 2 6 5 3 6 5 6 5 2 4 3 6 2 4 5 5 3 5 1 5 6 3 5 6 2 5 5 2 2 3 5 5 5 3 5 2 2 2 3 5 6 4 5 1 2 6 2 3 2 3 4 4 3 6 3 6 6 5 2 5 5 5 5 2 6 4 6 2 1 6 4 2 4 6 4 3 5 3 2 4 6 6 5 6 5 2 4 2 4 2 3 6 6 1 5 3 4 6 3 2 2 6 2 3 3 4 6 3 4 3 6 5 2 6 5 2 4 5 1 6 2 6 4 6 4 6 3 5 5 2 6 3 4 5 6 2 6 3 6 3 2 3 6 1 4 5 5 5 5 6 2 2 6 3 5 4 4 6 6 4 5 2 2 2 4 4 2 4 1 4 3 3 3 3 2 3 6 6 6 6 4 5 2 4 6 6 5 3 6 6 6 5 4 1 4 6 5 2 5 4 4 5 4 4 6 3 6 3 4 5 5 4 4 3 4 5 3 4 1 3 6 5 2 6 2 2 4 2 4 2 5 4 4 3 2 4 3 2 6 5 3 6 3 1 6 4 3 5 6 4 5 4 5 3 2 3 5 6 2 3 5 2 4 5 3 5 6 6 1 3 2 3 2 3 3 4 4 3 2 4 3 5 3 6 3 6 6 6 3 2 5 4 3 1 3 3 2 4 2 4 3 4 4 4 3 6 5 3 2 2 3 2 2 5 2 3 2 3 1 5 4 6 6 5 2 3 2 4 5 5 5 6 4 3 5 2 3 4 6 5 3 3 5 1 5 3 2 2 3 3 3 5 3 2 5 6 6 3 5 6 6 4 2 6 2 2 4 5 1 4 4 5 2 6 3 6 6 4 3 5 6 4 2 3 6 5 2 4 3 4 6 3 4 1 6 2 6 4 3 5 5 3 5 2 5 6 6 5 6 4 4 5 3 2 6 2 4 6 1 2 4 4 2 5 4 6 2 5 6 3 3 4 6 4 2 4 4 4 5 2 5 2 2 1 2 4 4 5 2 2 2 5 5 4 4 4 4 6 4 5 4 3 2 3 2 6 4 2 1 5 2 2 3 4 2 5 2 3 5 6 5 3 2 3 3 4 3 3 6 4 4 4 5 1 6 5 4 5 3 5 4 6 6 6 2 6 5 2 2 4 2 3 3 3 2 4 2 6 1 5 6 5 5 2 2 5 2 4 4 3 4 3 4 4 4 5 6 5 5 5 2 5 5 1 positivity_final/coxeter_matrices/E100000600000175000017500000000031007576410316021445 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett2_30000600000175000017500000000171007576410316023117 0ustar duclouxducloux000000000000001 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/E110000600000175000017500000000036207576410316021455 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett2_40000600000175000017500000000171007576410316023120 0ustar duclouxducloux000000000000001 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 4 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 4 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/star_4,4,40000600000175000017500000000052207576410316022621 0ustar duclouxducloux000000000000001 3 2 2 2 3 2 2 2 3 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 3 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 3 2 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett2_60000600000175000017500000000171007576410316023122 0ustar duclouxducloux000000000000001 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 6 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 6 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett2_70000600000175000017500000000171007576410316023123 0ustar duclouxducloux000000000000001 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 7 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 7 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/howlett2_80000600000175000017500000000171007576410316023124 0ustar duclouxducloux000000000000001 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 8 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 8 1 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/E120000600000175000017500000000044007576410316021453 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/E130000600000175000017500000000052207576410316021455 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/E140000600000175000017500000000061007576410316021454 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/E150000600000175000017500000000070207576410316021457 0ustar duclouxducloux000000000000001 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 3 2 2 2 2 2 2 2 2 2 2 2 3 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 3 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/star_3,3,30000600000175000017500000000031007576410316022611 0ustar duclouxducloux000000000000001 3 2 2 3 2 2 3 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 3 2 2 2 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 2 2 2 3 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/star_5,5,50000600000175000017500000000100007576410316022614 0ustar duclouxducloux000000000000001 3 2 2 2 2 3 2 2 2 2 3 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/star_5,5,80000600000175000017500000000132207576410316022626 0ustar duclouxducloux000000000000001 3 2 2 2 2 3 2 2 2 2 3 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/trial0000600000175000017500000000110207763766725022253 0ustar duclouxducloux000000000000001 3 2 2 2 3 2 2 2 3 2 2 2 3 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/coxeter_matrices/trial~0000600000175000017500000000100007763765210022432 0ustar duclouxducloux000000000000001 3 2 2 2 2 3 2 2 2 2 3 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 1 positivity_final/files.h0000600000175000017500000003420210011171251017073 0ustar duclouxducloux00000000000000/* This is files.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef FILES_H /* guard against multiple inclusions */ #define FILES_H #include "globals.h" namespace files { using namespace globals; }; /******** type declarations *************************************************/ namespace files { enum Header { bettiH, basisH, closureH, dufloH, extremalsH, ihBettiH, lCOrderH, lCellsH, lCellWGraphsH, lWGraphH, lrCOrderH, lrCellsH, lrCellWGraphsH, lrWGraphH, rCOrderH, rCellsH, rCellWGraphsH, rWGraphH, slocusH, sstratificationH, numHeaders}; struct AddHeckeTraits; struct HeckeTraits; struct OutputTraits; struct PolynomialTraits; struct PosetTraits; struct PartitionTraits; struct WgraphTraits; }; /******** function definitions **********************************************/ #include "hecke.h" #include "invkl.h" #include "kl.h" #include "uneqkl.h" #include "wgraph.h" namespace files { using namespace hecke; using namespace wgraph; // do _not_ use namespace kl! creates conflicts in coxgroup }; namespace files { template void appendCoefficient(String& str, const C& c, PolynomialTraits& traits); template void appendExponent(String& str, const E& e, PolynomialTraits& traits); template void appendHeckeMonomial(String& str, const M& m, const SchubertContext& p, const Interface& I, HeckeTraits& hTraits, PolynomialTraits& pTraits, const Length& l); void appendHomology(String& str, const Homology& h, OutputTraits& traits); template void appendMonomial(String& str, const C& c, const Ulong& e, PolynomialTraits& traits, const Ulong& d = 1, const long& m = 0); void appendModifier(String& str, const Ulong& d, const long& m, PolynomialTraits& traits); template void appendMuMark(String& str, const M& m, const SchubertContext& p, const Length& l, HeckeTraits& traits); template void appendPolynomial(String& str, const P& p, PolynomialTraits& traits, const Ulong& d = 1, const long& m = 0); void appendSeparator(String& str, const Ulong& n, HeckeTraits& traits); template void makeWGraph(WGraph& X, const List& c, const LFlags& f, KL& kl); void minReps(List& min, const Partition& pi, schubert::NFCompare& c); void pad(String& str, const Ulong& n, HeckeTraits& traits); template void printAsBasisElt(FILE* file, const H& h, const SchubertContext& p, Interface& I, OutputTraits& traits); void printBetti(FILE* file, const CoxNbr& y, const SchubertContext& p, OutputTraits& traits); void printCellOrder(FILE* file, const OrientedGraph& X, const SchubertContext& p, const Interface& I, PosetTraits& traits); void printCoatoms(FILE* file, const CoxNbr& y, const SchubertContext& p, const Interface& I, OutputTraits& traits); template void printClosure(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits); template void printCoefficient(FILE* file, const C& c, PolynomialTraits& traits); void printDescents(FILE* file, const LFlags& df, const LFlags& f, const Interface& I, WgraphTraits& traits); template void printDuflo(FILE* file, const List& d, const Partition& pi, KL& kl, const Interface& I, OutputTraits& traits); void printEltData(FILE* file, const CoxNbr& y, const SchubertContext& p, const Interface& I, OutputTraits& traits); template void printExponent(FILE* file, const E& e, PolynomialTraits& traits); template void printExtremals(FILE* file, const CoxNbr& y, const KL& kl, const Interface& I, OutputTraits& traits); void printHeader(FILE* file, const Header& header, OutputTraits& traits); template void printHeckeElt(FILE* file, const H& h, const SchubertContext& p, const Interface& I, OutputTraits& traits, const Length& l = undef_length); template void printHeckeElt(FILE* file, const H& h, const SchubertContext& p, const Interface& I, OutputTraits& traits, const Length& l = undef_length); template void printHeckeElt(FILE* file, const H& h, const Permutation& a, const SchubertContext& p, const Interface& I, HeckeTraits& hTraits, PolynomialTraits& pTraits, const Length& l = undef_length); void printHomology(FILE* file, const Homology& h, OutputTraits& traits); template void printIHBetti(FILE* file, const CoxNbr& y, KL& kl, OutputTraits& traits); template void printLCOrder(FILE* file, KL& kl, const Interface& I, OutputTraits& traits); template void printLCells(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits); template void printLCellWGraphs(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits); template void printLRCOrder(FILE* file, KL& kl, const Interface& I, OutputTraits& traits); template void printLRCells(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits); template void printLRCellWGraphs(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits); template void printLRWGraph(FILE* file, KL& kl, const Interface& I, OutputTraits& traits); template void printLWGraph(FILE* file, KL& kl, const Interface& I, OutputTraits& traits); template void printMonomial(FILE* file, const C& c, const Ulong& e, PolynomialTraits& traits, const Ulong& d = 1, const long& m = 0); void printModifier(FILE* file, const Ulong& d, const long& m, PolynomialTraits& traits); template void printMuMark(FILE* file, const M& m, const SchubertContext& p, const Length& l, HeckeTraits& traits); void printPartition(FILE* file, const Partition& pi, const SchubertContext& p, const Interface& I, PartitionTraits& traits); template void printPolynomial(FILE* file, const P& p, PolynomialTraits& traits, const Ulong& d = 1, const long& m = 0); template void printRCOrder(FILE* file, KL& kl, const Interface& I, OutputTraits& traits); template void printRCells(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits); template void printRCellWGraphs(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits); template void printRWGraph(FILE* file, KL& kl, const Interface& I, OutputTraits& traits); void printSeparator(FILE* file, const Ulong& n, HeckeTraits& traits); template void printSingularLocus(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits); template void printSingularStratification(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits); void printWGraph(FILE* file, const WGraph& X, const LFlags& f, const Interface& I, WgraphTraits& traits); template void printWGraphList(FILE* file, const Partition& pi, const LFlags& f, const Interface& I, KL& kl, OutputTraits& traits); template bool setTwoSided(const H& h, const Permutation& a, const SchubertContext& p, const Interface& I, HeckeTraits& hTraits, PolynomialTraits& pTraits, const Length& l = undef_length); void sortLists(List >& lc, schubert::NFCompare& nfc, Permutation& a); void writeClasses(List >& lc, const Partition& pi); }; /******** type definitions **************************************************/ namespace files { struct PolynomialTraits { String prefix; String postfix; String indeterminate; String sqrtIndeterminate; String posSeparator; String negSeparator; String product; String exponent; String expPrefix; String expPostfix; String zeroPol; String one; String negOne; String modifierPrefix; String modifierPostfix; String modifierSeparator; bool printExponent; bool printModifier; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(PolynomialTraits));} PolynomialTraits(Pretty); PolynomialTraits(Terse); PolynomialTraits(GAP); ~PolynomialTraits(); }; struct HeckeTraits { String prefix; String postfix; String evenSeparator; String oddSeparator; String monomialPrefix; String monomialPostfix; String monomialSeparator; String muMark; String hyphens; Ulong lineSize; Ulong indent; Ulong evenWidth; Ulong oddWidth; char padChar; bool doShift; bool reversePrint; bool twoSided; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(HeckeTraits));} HeckeTraits(const Interface& I, Pretty); HeckeTraits(const Interface& I, Terse); HeckeTraits(const Interface& I, GAP); virtual ~HeckeTraits(); }; struct AddHeckeTraits:public HeckeTraits { // Hecke traits for additive output GroupEltInterface* eltTraits; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(AddHeckeTraits));} AddHeckeTraits(const Interface& I, Pretty); AddHeckeTraits(const Interface& I, Terse); AddHeckeTraits(const Interface& I, GAP); ~AddHeckeTraits(); }; struct PartitionTraits { String prefix; String postfix; String separator; String classPrefix; String classPostfix; String classSeparator; String classNumberPrefix; String classNumberPostfix; bool printClassNumber; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(PartitionTraits));} PartitionTraits(Pretty); PartitionTraits(Terse); PartitionTraits(GAP); ~PartitionTraits(); }; struct PosetTraits { String prefix; String postfix; String separator; String edgePrefix; String edgePostfix; String edgeSeparator; String nodePrefix; String nodePostfix; Ulong nodeShift; bool printNode; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(PosetTraits));} PosetTraits(Pretty); PosetTraits(Terse); PosetTraits(GAP); ~PosetTraits(); }; struct WgraphTraits { String prefix; String postfix; String separator; String edgeListPrefix; String edgeListPostfix; String edgeListSeparator; String edgePrefix; String edgePostfix; String edgeSeparator; String nodePrefix; String nodePostfix; String nodeSeparator; String nodeNumberPrefix; String nodeNumberPostfix; Ulong nodeShift; int padSize; bool hasPadding; bool printNodeNumber; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(WgraphTraits));} WgraphTraits(Pretty); WgraphTraits(Terse); WgraphTraits(GAP); ~WgraphTraits(); }; struct OutputTraits { // strings String versionString; String typeString; // header file names String header[numHeaders]; String prefix[numHeaders]; String postfix[numHeaders]; bool hasHeader[numHeaders]; // prettyfying strings for printouts String closureSeparator1; String closureSeparator2; String closureSeparator3; String closureSeparator4; String closureSeparator5; String closureSeparator6; String eltList; String singularLocus; String singularStratification; String emptySingularLocus; String emptySingularStratification; // list formatting String bettiPrefix; String bettiPostfix; String bettiSeparator; String bettiRankPrefix; String bettiRankPostfix; String cellNumberPrefix; String cellNumberPostfix; String closureSizePrefix; String closureSizePostfix; String coatomPrefix; String coatomPostfix; String coatomSeparator; String compCountPrefix; String compCountPostfix; String dufloPrefix; String dufloPostfix; String dufloSeparator; String dufloListPrefix; String dufloListPostfix; String dufloListSeparator; String dufloNumberPrefix; String dufloNumberPostfix; String eltNumberPrefix; String eltNumberPostfix; String eltListPrefix; String eltListPostfix; String eltListSeparator; String eltPrefix; String eltPostfix; String eltDataPrefix; String eltDataPostfix; String graphListPrefix; String graphListPostfix; String graphListSeparator; String lDescentPrefix; String lDescentPostfix; String rDescentPrefix; String rDescentPostfix; String lengthPrefix; String lengthPostfix; String closeString; String bettiHyphens; Ulong lineSize; // traits for the output of a polynomial PolynomialTraits polTraits; // traits for the output of a Hecke element HeckeTraits heckeTraits; AddHeckeTraits addHeckeTraits; // traits for the output of a partition PartitionTraits partitionTraits; // traits for the output of a W-graph WgraphTraits wgraphTraits; // traits for the output of a poset PosetTraits posetTraits; // flags bool printBettiRank; bool printCellNumber; bool printClosureSize; bool printCoatoms; bool printCompCount; bool printDufloNumber; bool printEltDescents; bool printElt; bool printEltData; bool printEltNumber; bool printLength; bool printType; bool printVersion; bool hasBettiPadding; // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void* operator new(size_t size, void* ptr) {return ptr;} void operator delete(void* ptr) {return arena().free(ptr,sizeof(OutputTraits));} void operator delete(void* p1, void* p2) {}; OutputTraits(const CoxGraph& G, const Interface& I, Pretty); OutputTraits(const CoxGraph& G, const Interface& I, Terse); OutputTraits(const CoxGraph& G, const Interface& I, GAP); ~OutputTraits(); // manipulators void setBasisTraits(HeckeTraits& hTraits); void setDefaultTraits(HeckeTraits& hTraits); }; }; /******** inline definitions *************************************************/ #include "files.hpp" #endif positivity_final/files.hpp0000600000175000017500000006217710011171251017447 0ustar duclouxducloux00000000000000/* This is files.hpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "cells.h" /**************************************************************************** This file contains the definition of the following function templates, declared in files.hpp : - appendCoefficient(str,c,traits) : append a polynomial-coefficient to str; - appendHeckeMonomial(str,m,p,I,pTraits,hTraits,l) : appends a Hecke- monomial to str; - appendMonomial(str,c,e,traits,d,m) : appends a (possibly shifted) monomial to str; part of appendPolynomial; - appendMuMark(str,m,p,l,traits) : appends the marking for non-zero mu-coefficients; - appendPolynomial(str,p,traits,d,m) : appends a (possibly shifted) polynomial to str; - printAsBasisElt(file,h,p,I,G,traits) : prints the Hecke element h, assumed to contain an element of the k-l basis, according to the given output traits; - printCoefficient(file,c,traits) : like appendCoefficient; - printHeckeElt(file,h,p,I,a,hTraits,pTraits,l) : same as preceding one, but data is sorted using the permutation a; - printHeckeMonomial(file,m,p,I,pTraits,hTraits,l) : like appendHeckeMonomial; - printLCOrder(file,kl,I,G,traits) : outputs the left cell ordering as an abstract poset; - printLRCOrder(file,kl,I,G,traits) : outputs the two-sided cell ordering as an abstract poset; - printMonomial(file,c,e,traits,d,m) : like appendMonomial; - printMuMark(file,m,p,l,traits) : like appendMuMark; - printPolynomial(file,p,traits,d,m) : like appendPolynomial; - printRCOrder(file,kl,I,G,traits) : outputs the right cell ordering as an abstract poset; - setTwoSided(h,p,I,a,hTraits,pTraits,l) : same as preceding one, with the data in h permuted by a; *****************************************************************************/ namespace files { template void appendCoefficient(String& str, const C& c, PolynomialTraits& traits) { io::append(str,c); return; } template void appendExponent(String& str, const E& e, PolynomialTraits& traits) /* Appends the exponent e*d+m according to the traits. */ { if (!traits.printExponent) return; io::append(str,traits.exponent); io::append(str,traits.expPrefix); io::append(str,static_cast(e)); io::append(str,traits.expPostfix); return; } template void appendHeckeMonomial(String& str, const M& m, const SchubertContext& p, const Interface& I, HeckeTraits& hTraits, PolynomialTraits& pTraits, const Length& l) { using namespace klsupport; typedef typename M::PolType P; PolynomialType ptype = P::polType(); Length lx = p.length(m.x()); Ulong d = 1; long q = 0; String indeterminate = pTraits.indeterminate; // back up if ((l != undef_length) && hTraits.doShift) { // set shift parameters d = 2; q = lx-l; pTraits.indeterminate = pTraits.sqrtIndeterminate; } io::append(str,hTraits.monomialPrefix); if (hTraits.reversePrint) { appendPolynomial(str,m.pol(),pTraits,d,q); io::append(str,hTraits.monomialSeparator); p.append(str,m.x(),I); } else { p.append(str,m.x(),I); io::append(str,hTraits.monomialSeparator); appendPolynomial(str,m.pol(),pTraits,d,q); } io::append(str,hTraits.monomialPostfix); if ((ptype == KLPOL) && (l != undef_length)) appendMuMark(str,m,p,l,hTraits); pTraits.indeterminate = indeterminate; return; } template void appendMonomial(String& str, const C& c, const Ulong& e, PolynomialTraits& traits, const Ulong& d, const long& m) /* We append a monomial of the form c.q^{e*d+m}. */ { long e_s = e*d+m; if (e_s == 0) appendCoefficient(str,c,traits); else { if (c == 1) io::append(str,traits.one); else if (-c == 1) io::append(str,traits.negOne); else { appendCoefficient(str,c,traits); io::append(str,traits.product); } io::append(str,traits.indeterminate); if (e_s != 1) { appendExponent(str,e_s,traits); } } return; } template void appendMuMark(String& str, const M& m, const SchubertContext& p, const Length& l, HeckeTraits& traits) /* Appends a marker if the degree of the polynomial is as big as it can be. Here l is the lenth of the y-element of the basis. */ { Length lx = p.length(m.x()); if (static_cast(2*m.pol().deg()) == static_cast(l-lx-1)) io::append(str,traits.muMark); return; } template void appendPolynomial(String& str, const P& p, PolynomialTraits& traits, const Ulong& d, const long& m) { if (p.isZero()) { io::append(str,traits.zeroPol); return; } if (traits.printModifier) appendModifier(str,d,m,traits); io::append(str,traits.prefix); bool firstTerm = true; for (Ulong j = 0; j <= p.deg(); ++j) { if (p[j] == 0) continue; if (firstTerm) // first term firstTerm = false; else { // append separator if (p[j] > 0) io::append(str,traits.posSeparator); else io::append(str,traits.negSeparator); } appendMonomial(str,p[j],j,traits,d,m); } io::append(str,traits.postfix); return; } template void makeWGraph(WGraph& X, const List& c, const LFlags& f, KL& kl) /* Puts in X the W-graph for the part of the context contained in c. The flags in f are either all left, all right or all two-sided generators. */ { SubSet q(kl.size()); for (Ulong j = 0; j < c.size(); ++j) q.add(c[j]); if (!(f&1)) // left descents cells::lWGraph(X,q,kl); else if (!(f >> kl.rank())) // right descents cells::rWGraph(X,q,kl); else // two-sided descents cells::lrWGraph(X,q,kl); return; } template void printAsBasisElt(FILE* file, const H& h, const SchubertContext& p, Interface& I, OutputTraits& traits) /* This function prints one element of the k-l basis, according to the given output traits. */ { // sorting of the element typedef typename H::eltType::PolType P; hecke::NFCompare

nfc(p,I.order()); // printing of the basis element proper GroupEltInterface GI(I.outInterface()); I.setOut(*traits.addHeckeTraits.eltTraits); HeckeTraits& hTraits = traits.addHeckeTraits; PolynomialTraits& pTraits = traits.polTraits; CoxNbr y = h[h.size()-1].x(); Permutation a(0); sortI(h,nfc,a); io::print(file,traits.prefix[basisH]); printHeckeElt(file,h,a,p,I,hTraits,pTraits,p.length(y)); io::print(file,traits.postfix[basisH]); io::print(file,"\n"); I.setOut(GI); return; } template void printClosure(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits) /* Assuming that h contains the extremal pairs for a given element y of the group, and the corresponding k-l polynomials, this prints out all the data : it combines coatoms, extremals, singular locus, singular stratification, betti numbers and IH betti numbers. */ { const SchubertContext& p = kl.schubert(); // print out y and the descent sets if (traits.printEltData) { // print data about y printEltData(file,y,p,I,traits); fprintf(file,"\n"); } // print out the coatoms if (traits.printCoatoms) { printCoatoms(file,y,p,I,traits); fprintf(file,"\n"); } // print out the extremal pairs io::print(file,traits.closureSeparator1); printExtremals(file,y,kl,I,traits); // print out the singular locus kl::HeckeElt h(0); genericSingularities(h,y,kl); if (h.size() == 0) { // Schubert variety is smooth io::print(file,traits.closureSeparator2); io::print(file,traits.emptySingularLocus); fprintf(file,"\n"); io::print(file,traits.emptySingularStratification); fprintf(file,"\n"); } else { io::print(file,traits.closureSeparator3); printSingularLocus(file,y,kl,I,traits); // print out the singular stratification io::print(file,traits.closureSeparator4); printSingularStratification(file,y,kl,I,traits); } // print betti numbers io::print(file,traits.closureSeparator5); printBetti(file,y,p,traits); // print IH betti numbers io::print(file,traits.closureSeparator6); printIHBetti(file,y,kl,traits); return; } template void printCoefficient(FILE* file, const C& c, PolynomialTraits& traits) { fprintf(file,"%ld",static_cast(c)); return; } template void printDuflo(FILE* file, const List& dl, const Partition& pi, KL& kl, const Interface& I, OutputTraits& traits) /* This function prints out the Duflo involutions on the file. The list d is the list of Duflo involutions; the partition pi is the partition of the group into left cells. We print out the Duflo involutions in the usual ordering in which we print out the left cells, viz. order the cells by shortlex ordering of their shortlex-smallest elements. */ { const SchubertContext& p = kl.schubert(); // print duflo involutions List min(0); schubert::NFCompare nfc(p,I.order()); minReps(min,pi,nfc); Permutation a(0); sortI(min,nfc,a); int d = digits(dl.size()-1,10); io::print(file,traits.prefix[dufloH]); io::print(file,traits.dufloListPrefix); for (Ulong j = 0; j < dl.size(); ++j) { if (traits.printDufloNumber) { io::print(file,traits.dufloNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.dufloNumberPostfix); } const kl::KLPol& pol = kl.klPol(0,dl[a[j]]); io::print(file,traits.dufloPrefix); p.print(file,dl[a[j]],I); io::print(file,traits.dufloSeparator); printPolynomial(file,pol,traits.polTraits); io::print(file,traits.dufloPostfix); if (j+1 < dl.size()) // there is more to come io::print(file,traits.dufloListSeparator); } io::print(file,traits.dufloListPostfix); io::print(file,traits.postfix[dufloH]); fprintf(file,"\n"); return; } template void printExponent(FILE* file, const E& e, PolynomialTraits& traits) /* Prints the exponent d*e+m to the file. */ { if (!traits.printExponent) return; io::print(file,traits.exponent); io::print(file,traits.expPrefix); fprintf(file,"%ld",static_cast(e)); io::print(file,traits.expPostfix); return; } template void printExtremals(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits) { kl::HeckeElt h(0); kl.row(h,y); if (ERRNO) { Error(ERRNO); return; } const SchubertContext& p = kl.schubert(); Length ly = p.length(y); io::print(file,traits.prefix[extremalsH]); printHeckeElt(file,h,p,I,traits,ly); io::print(file,traits.postfix[extremalsH]); fprintf(file,"\n"); return; } template void printHeckeElt(FILE* file, const H& h, const SchubertContext& p, const Interface& I, OutputTraits& traits, const Length& l) /* Does the printing of the sorted Hecke algebra element. */ { typedef typename H::eltType::PolType P; hecke::NFCompare

nfc(p,I.order()); Permutation a(0); sortI(h,nfc,a); printHeckeElt(file,h,a,p,I,traits.heckeTraits,traits.polTraits,l); return; } template void printHeckeElt(FILE* file, const H& h, const Permutation& a, const SchubertContext& p, const Interface& I, HeckeTraits& hTraits, PolynomialTraits& pTraits, const Length& l) /* Prints out the Hecke algebra element h, permuted according to the permutation a, following the given traits. */ { String buf(0); bool oldTS = setTwoSided(h,a,p,I,hTraits,pTraits,l); io::print(file,hTraits.prefix); for (Ulong j = 0; j < h.size(); ++j) { appendHeckeMonomial(buf,h[a[j]],p,I,hTraits,pTraits,l); if (j < h.size()-1) // there is more to come appendSeparator(buf,j,hTraits); pad(buf,j,hTraits); if (hTraits.lineSize) foldLine(file,buf,hTraits.lineSize,hTraits.indent,hTraits.hyphens.ptr()); else io::print(file,buf); reset(buf); } io::print(file,hTraits.postfix); hTraits.twoSided = oldTS; return; } template void printIHBetti(FILE* file, const CoxNbr& y, KL& kl, OutputTraits& traits) { Homology h(0); ihBetti(h,y,kl); io::print(file,traits.prefix[ihBettiH]); printHomology(file,h,traits); io::print(file,traits.postfix[ihBettiH]); fprintf(file,"\n"); return; } template void printLCOrder(FILE* file, KL& kl, const Interface& I, OutputTraits& traits) { // make graph OrientedGraph X(0); cells::lGraph(X,kl); // printout data io::print(file,traits.prefix[lCOrderH]); printCellOrder(file,X,kl.schubert(),I,traits.posetTraits); io::print(file,traits.postfix[lCOrderH]); io::print(file,"\n"); return; } template void printLCells(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits) { // print out cells io::print(file,traits.prefix[lCellsH]); printPartition(file,lp,kl.schubert(),I,traits.partitionTraits); io::print(file,traits.postfix[lCellsH]); io::print(file,"\n"); return; } template void printLCellWGraphs(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits) { // set flag parameter LFlags f = leqmask[kl.rank()-1] << kl.rank(); // print W-graphs io::print(file,traits.prefix[lCellWGraphsH]); printWGraphList(file,lp,f,kl,I,traits); io::print(file,traits.postfix[lCellWGraphsH]); fprintf(file,"\n"); return; } template void printLRCOrder(FILE* file, KL& kl, const Interface& I, OutputTraits& traits) { // make graph OrientedGraph X(0); cells::lrGraph(X,kl); // printout data io::print(file,traits.prefix[lrCOrderH]); printCellOrder(file,X,kl.schubert(),I,traits.posetTraits); io::print(file,traits.postfix[lrCOrderH]); io::print(file,"\n"); return; } template void printLRCells(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits) { // print out cells io::print(file,traits.prefix[lrCellsH]); printPartition(file,lp,kl.schubert(),I,traits.partitionTraits); io::print(file,traits.postfix[lrCellsH]); io::print(file,"\n"); return; } template void printLRCellWGraphs(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits) { // set flag parameter LFlags f = leqmask[2*kl.rank()-1]; // print graphs io::print(file,traits.prefix[lrCellWGraphsH]); printWGraphList(file,lp,f,kl,I,traits); io::print(file,traits.postfix[lrCellWGraphsH]); fprintf(file,"\n"); return; } template void printLRWGraph(FILE* file, KL& kl, const Interface& I, OutputTraits& traits) /* This function prints out the W-graph data for the full context; the output contains only the edges of the graph which lie within the current context, but it is guaranteed to contain all those edges. */ { // print element list int d = digits(kl.size()-1,10); io::print(file,traits.eltList); io::print(file,traits.eltListPrefix); for (Ulong j = 0; j < kl.size(); ++j) { if (traits.printEltNumber) { io::print(file,traits.eltNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.eltNumberPostfix); } kl.schubert().print(file,j,I); if (j+1 < kl.size()) // there is more to come io::print(file,traits.eltListSeparator); } io::print(file,traits.eltListPostfix); io::print(file,traits.closeString); fprintf(file,"\n"); // print graph io::print(file,traits.prefix[lrWGraphH]); WGraph X(0); cells::lrWGraph(X,kl); LFlags f = leqmask[2*kl.rank()-1]; printWGraph(file,X,f,I,traits.wgraphTraits); io::print(file,traits.postfix[lrWGraphH]); fprintf(file,"\n"); return; } template void printLWGraph(FILE* file, KL& kl, const Interface& I, OutputTraits& traits) /* This function prints out the W-graph data for the full context; the output contains only the edges of the graph which lie within the current context, but it is guaranteed to contain all those edges. */ { // print element list int d = digits(kl.size()-1,10); io::print(file,traits.eltList); io::print(file,traits.eltListPrefix); for (Ulong j = 0; j < kl.size(); ++j) { if (traits.printEltNumber) { io::print(file,traits.eltNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.eltNumberPostfix); } kl.schubert().print(file,j,I); if (j+1 < kl.size()) // there is more to come io::print(file,traits.eltListSeparator); } io::print(file,traits.eltListPostfix); io::print(file,traits.closeString); fprintf(file,"\n"); // print graph io::print(file,traits.prefix[lWGraphH]); WGraph X(0); cells::lWGraph(X,kl); LFlags f = leqmask[kl.rank()-1] << kl.rank(); printWGraph(file,X,f,I,traits.wgraphTraits); io::print(file,traits.postfix[lWGraphH]); fprintf(file,"\n"); return; } template void printMonomial(FILE* file, const C& c, const Ulong& e, PolynomialTraits& traits, const Ulong& d, const long& m) /* We print a monomial of the form c.q^e, where it is guaranteed that c is > 0. It is assumed that c can be printed out as a long integer; this should probably also be a parameter. */ { long e_s = e*d+m; if (e_s == 0) printCoefficient(file,c,traits); else { if (c == 1) io::print(file,traits.one); else if (-c == 1) io::print(file,traits.negOne); else { printCoefficient(file,c,traits); io::print(file,traits.product); } io::print(file,traits.indeterminate); if (e_s != 1) { printExponent(file,e_s,traits); } } return; } template void printMuMark(FILE* file, const M& m, const SchubertContext& p, const Length& l, HeckeTraits& traits) /* Prints a marker if the degree of the polynomial is as big as it can be. Here l is the length of the y-element of the basis. */ { Length lx = p.length(m.x()); if (static_cast(2*m.pol().deg()) == static_cast(l-lx-1)) io::print(file,traits.muMark); return; } template void printPolynomial(FILE* file, const P& p, PolynomialTraits& traits, const Ulong& d, const long& m) { if (p.isZero()) { io::print(file,traits.zeroPol); return; } if (traits.printModifier) printModifier(file,d,m,traits); io::print(file,traits.prefix); bool firstTerm = true; for (Ulong j = 0; j <= p.deg(); ++j) { if (p[j] == 0) continue; if (firstTerm) // first term firstTerm = false; else { // print separator if (p[j] > 0) io::print(file,traits.posSeparator); else io::print(file,traits.negSeparator); } printMonomial(file,p[j],j,traits,d,m); } io::print(file,traits.postfix); return; } template void printRCOrder(FILE* file, KL& kl, const Interface& I, OutputTraits& traits) { // make graph OrientedGraph X(0); cells::rGraph(X,kl); // printout data io::print(file,traits.prefix[rCOrderH]); printCellOrder(file,X,kl.schubert(),I,traits.posetTraits); io::print(file,traits.postfix[rCOrderH]); io::print(file,"\n"); return; } template void printRCells(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits) { // print out cells io::print(file,traits.prefix[rCellsH]); printPartition(file,lp,kl.schubert(),I,traits.partitionTraits); io::print(file,traits.postfix[rCellsH]); io::print(file,"\n"); return; } template void printRCellWGraphs(FILE* file, const Partition& lp, KL& kl, const Interface& I, OutputTraits& traits) { LFlags f = leqmask[kl.rank()-1]; io::print(file,traits.prefix[rCellWGraphsH]); printWGraphList(file,lp,f,kl,I,traits); io::print(file,traits.postfix[rCellWGraphsH]); fprintf(file,"\n"); return; } template void printRWGraph(FILE* file, KL& kl, const Interface& I, OutputTraits& traits) /* This function prints out the W-graph data for the full context; the output contains only the edges of the graph which lie within the current context, but it is guaranteed to contain all those edges. */ { // print element list int d = digits(kl.size()-1,10); io::print(file,traits.eltList); io::print(file,traits.eltListPrefix); for (Ulong j = 0; j < kl.size(); ++j) { if (traits.printEltNumber) { io::print(file,traits.eltNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.eltNumberPostfix); } kl.schubert().print(file,j,I); if (j+1 < kl.size()) // there is more to come io::print(file,traits.eltListSeparator); } io::print(file,traits.eltListPostfix); io::print(file,traits.closeString); fprintf(file,"\n"); // print graph io::print(file,traits.prefix[rWGraphH]); WGraph X(0); cells::rWGraph(X,kl); LFlags f = leqmask[kl.rank()-1]; printWGraph(file,X,f,I,traits.wgraphTraits); io::print(file,traits.postfix[rWGraphH]); fprintf(file,"\n"); return; } template void printSingularLocus(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits) { const SchubertContext& p = kl.schubert(); kl::HeckeElt hs(0); genericSingularities(hs,y,kl); if (hs.size() == 0) { // singular locus is empty io::print(file,traits.emptySingularLocus); fprintf(file,"\n"); return; } Length ly = p.length(y); io::print(file,traits.prefix[slocusH]); printHeckeElt(file,hs,p,I,traits,ly); io::print(file,traits.postfix[slocusH]); fprintf(file,"\n"); if (traits.printCompCount) { io::print(file,traits.compCountPrefix); fprintf(file,"%lu",hs.size()); io::print(file,traits.compCountPostfix); io::print(file,traits.closeString); fprintf(file,"\n"); } return; } template void printSingularStratification(FILE* file, const CoxNbr& y, KL& kl, const Interface& I, OutputTraits& traits) { const SchubertContext& p = kl.schubert(); kl::HeckeElt h(0); kl.row(h,y); if (ERRNO) { Error(ERRNO); return; } kl::HeckeElt hs(0); hecke::singularStratification(hs,h,p); if (hs.size() == 0) { // singular locus is empty io::print(file,traits.emptySingularStratification); fprintf(file,"\n"); return; } Length ly = p.length(y); io::print(file,traits.prefix[sstratificationH]); printHeckeElt(file,hs,p,I,traits,ly); io::print(file,traits.postfix[sstratificationH]); fprintf(file,"\n"); if (traits.printCompCount) { io::print(file,traits.compCountPrefix); fprintf(file,"%lu",hs.size()); io::print(file,traits.compCountPostfix); io::print(file,traits.closeString); fprintf(file,"\n"); } return; } template void printWGraphList(FILE* file, const Partition& pi, const LFlags& f, KL& kl, const Interface& I, OutputTraits& traits) /* This function prints out the W-graphs of the classes of the partition pi. The bitset f flags either all left, all right or all generators; it is assumed that the classes of f are actually W-graphs (they could for instance be intervals in the poset of cells). The order of the cells, ant the ordering within each cell, are as for printPartition. */ { const SchubertContext& p = kl.schubert(); // write out cells List > lc(0); writeClasses(lc,pi); // sort cells schubert::NFCompare nfc(p,I.order()); Permutation a(0); sortLists(lc,nfc,a); int d = digits(lc.size()-1,10); WgraphTraits& wTraits = traits.wgraphTraits; Ulong oldPadSize = wTraits.padSize; wTraits.padSize = d + traits.cellNumberPrefix.length() + traits.cellNumberPostfix.length(); // print out graphs io::print(file,traits.graphListPrefix); for (Ulong j = 0; j < lc.size(); ++j) { if (traits.printCellNumber) { io::print(file,traits.cellNumberPrefix); fprintf(file,"%*lu",d,j); io::print(file,traits.cellNumberPostfix); } WGraph X(0); makeWGraph(X,lc[a[j]],f,kl); printWGraph(file,X,f,I,wTraits); if (j+1 < lc.size()) io::print(file,traits.graphListSeparator); } io::print(file,traits.graphListPostfix); wTraits.padSize = oldPadSize; return; } template bool setTwoSided(const H& h, const Permutation& a, const SchubertContext& p, const Interface& I, HeckeTraits& hTraits, PolynomialTraits& pTraits, const Length& l) /* This function decides between one- and two-sided output. Currently it is used only in pretty mode. It works by setting the value of *traits.twoSided to 0 or 1. What the function does is go through the list of entries in h, and check if each entry fits in the odd- or even width set by the traits. If yes, we do a two-sided printout. Return value is the previous value of *traits.twoSided, so that it can be restored afterward. */ { if (!hTraits.twoSided) // never do twosided output return false; // if we get here, *traits.twoSided is true String buf(0); for (Ulong j = 0; j < h.size(); ++j) { appendHeckeMonomial(buf,h[a[j]],p,I,hTraits,pTraits,l); if (j < h.size()-1) // there is more to come appendSeparator(buf,j,hTraits); if (j%2 && hTraits.oddWidth) { // look at odd side if (buf.length() >= hTraits.oddWidth) { // not fit or fit tight hTraits.twoSided = false; break; } } if (!(j%2) && hTraits.evenWidth) { // look at even side if (buf.length() >= hTraits.evenWidth) { // not fit or fit tight hTraits.twoSided = false; break; } } reset(buf); } return true; } }; positivity_final/general.cpp0000600000175000017500000000574210011171251017750 0ustar duclouxducloux00000000000000/* This is general.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "general.h" /************************************************************************* Chapter I -- Constructors and destructors. This section contains constructors (no destructors!) for the types in this module. They will be used as the default constructors for CoxGroup objects. - GeneralCoxGroup(x,l); - MedRankCoxGroup(x,l) : rank <= MEDRANK_MAX; - SmallRankCoxGroup(x,l) : rank <= SMALLRANK_MAX; *************************************************************************/ namespace general { GeneralCoxGroup::GeneralCoxGroup(const Type& x, const Rank& l) :CoxGroup(x,l) /* Initializes a GeneralCoxGroup structure of the given type and rank. */ { if (ERRNO) /* problem with the CoxGroup initialization */ return; } GeneralCoxGroup::~GeneralCoxGroup() /* Virtual destructor for a GeneralCoxGroup. Currently, nothing has to be done. */ {} BigRankCoxGroup::BigRankCoxGroup(const Type& x, const Rank& l) :GeneralCoxGroup(x,l) /* Initializes a GeneralCoxGroup structure of the given type and rank. Used when MEDRANK_MAX < rank. */ {} BigRankCoxGroup::~BigRankCoxGroup() /* Virtual destructor for a BigRankCoxGroup. Currently, nothing has to be done. */ {} GeneralBRCoxGroup::GeneralBRCoxGroup(const Type& x, const Rank& l) :BigRankCoxGroup(x,l) {} GeneralBRCoxGroup::~GeneralBRCoxGroup() /* Non-virtual destructor for the GeneralBRCoxGroup class. Currently, nothing has to be done. */ {} MedRankCoxGroup::MedRankCoxGroup(const Type& x, const Rank& l) :GeneralCoxGroup(x,l) /* Initializes a GeneralCoxGroup structure of the given type and rank. Used when SMALLRANK_MAX < rank <= MEDRANK_MAX. */ { if (ERRNO) return; mintable().fill(graph()); /* an error is set here in case of failure */ return; } MedRankCoxGroup::~MedRankCoxGroup() /* Virtual destructor for a MedRankCoxGroup. Currently, nothing has to be done; the mintable destruction is the job of the CoxGroup destructor. */ {} GeneralMRCoxGroup::GeneralMRCoxGroup(const Type& x, const Rank& l) :MedRankCoxGroup(x,l) {} GeneralMRCoxGroup::~GeneralMRCoxGroup() /* Non-virtual destructor for the GeneralMRCoxGroup class. Currently, nothing has to be done. */ {} SmallRankCoxGroup::SmallRankCoxGroup(const Type& x, const Rank& l) :MedRankCoxGroup(x,l) /* Initializes a GeneralCoxGroup structure of the given type and rank. Used when rank < SMALLRANK_MAX. */ { if (ERRNO) /* error in MedRankCoxGroup initialization */ return; } SmallRankCoxGroup::~SmallRankCoxGroup() /* Virtual destructor for a SmallRankCoxGroup. Currently, nothing has to be done. */ {} GeneralSRCoxGroup::GeneralSRCoxGroup(const Type& x, const Rank& l) :SmallRankCoxGroup(x,l) {} GeneralSRCoxGroup::~GeneralSRCoxGroup() /* Non-virtual destructor for the GeneralSRCoxGroup class. Currently, nothing has to be done. */ {} }; positivity_final/general.h0000600000175000017500000000645010011171251017412 0ustar duclouxducloux00000000000000/* This is general.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef GENERAL_H /* guard against multiple inclusions */ #define GENERAL_H #include "globals.h" #include "coxgroup.h" namespace general { using namespace globals; using namespace coxgroup; }; /******** type declarations **************************************************/ namespace general { class GeneralCoxGroup; class BigRankCoxGroup; class GeneralBRCoxGroup; class MedRankCoxGroup; class GeneralMRCoxGroup; class SmallRankCoxGroup; class GeneralSRCoxGroup; }; /********* type definitions **************************************************/ namespace general { class GeneralCoxGroup : public CoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralCoxGroup));} GeneralCoxGroup(const Type& x, const Rank& l); virtual ~GeneralCoxGroup(); /* accessors */ virtual CoxSize order() const; /* inlined */ }; class BigRankCoxGroup : public GeneralCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(BigRankCoxGroup));} BigRankCoxGroup(const Type& x, const Rank& l); virtual ~BigRankCoxGroup(); }; class GeneralBRCoxGroup:public BigRankCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralBRCoxGroup));} GeneralBRCoxGroup(const Type& x, const Rank& l); ~GeneralBRCoxGroup(); }; class MedRankCoxGroup : public GeneralCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(MedRankCoxGroup));} MedRankCoxGroup(const Type& x, const Rank& l); virtual ~MedRankCoxGroup(); }; class GeneralMRCoxGroup:public MedRankCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralMRCoxGroup));} GeneralMRCoxGroup(const Type& x, const Rank& l); ~GeneralMRCoxGroup(); }; class SmallRankCoxGroup : public MedRankCoxGroup { public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(SmallRankCoxGroup));} SmallRankCoxGroup(const Type& x, const Rank& l); virtual ~SmallRankCoxGroup(); }; class GeneralSRCoxGroup:public SmallRankCoxGroup { /* leaf class */ public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralSRCoxGroup));} GeneralSRCoxGroup(const Type& x, const Rank& l); ~GeneralSRCoxGroup(); }; }; /******** inline definitions *************************************************/ namespace general { inline CoxSize GeneralCoxGroup::order() const {return undef_coxsize;} }; #endif positivity_final/graph.cpp0000600000175000017500000011315410011171251017431 0ustar duclouxducloux00000000000000/* This is graph.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "graph.h" #include "directories.h" #include "interactive.h" namespace { using namespace graph; CoxSize dihedralOrder(CoxGraph& G, LFlags I); ParSize extrQuotOrder(CoxGraph& G, LFlags I, Generator s); void fillCoxAMatrix(CoxMatrix& m, Rank l); void fillCoxBMatrix(CoxMatrix& m, Rank l); void fillCoxDMatrix(CoxMatrix& m, Rank l); void fillCoxEMatrix(CoxMatrix& m, Rank l); void fillCoxFMatrix(CoxMatrix& m, Rank l); void fillCoxGMatrix(CoxMatrix& m); void fillCoxHMatrix(CoxMatrix& m, Rank l); void fillCoxIMatrix(CoxMatrix& m); void fillCoxaMatrix(CoxMatrix& m, Rank l); void fillCoxbMatrix(CoxMatrix& m, Rank l); void fillCoxcMatrix(CoxMatrix& m, Rank l); void fillCoxdMatrix(CoxMatrix& m, Rank l); void fillCoxeMatrix(CoxMatrix& m, Rank l); void fillCoxfMatrix(CoxMatrix& m, Rank l); void fillCoxgMatrix(CoxMatrix& m); void fillCoxXMatrix(CoxMatrix& m, const Rank& l, const Type& t); void fillCoxYMatrix(CoxMatrix& m, Rank l); CoxSize finiteOrder(const Type& type, const Rank& rank); Ulong gcd(Ulong a, Ulong b); const Type& irrType(CoxGraph& G, LFlags I); Generator lastGenerator(CoxGraph& G, LFlags I); ParSize lastQuotOrder(const Type& type, Rank rank); void makeCoxMatrix(CoxMatrix& m, const Type& x, const Rank& l); void makeStar(List&star, const CoxMatrix& m, const Rank& l); void makeStarOps(List&, const CoxMatrix& m, const Rank& l); CoxEntry maxCoefficient(CoxGraph& G, LFlags I); CoxEntry minCoefficient(CoxGraph& G, LFlags I); CoxSize A_order(Rank rank); CoxSize B_order(Rank rank); CoxSize D_order(Rank rank); }; /**************************************************************************** Chapter I -- The CoxGraph class. The CoxGraph class provides access to the various data contained in the Coxeter matrix : the matrix itself, and the underlying graph structure. The following functions are provided : - CoxGraph(x,l) : constructs a CoxGraph of type x and rank l; - ~CoxGraph() : not implemented yet; - component(I,s) : returns the connected component of s in I; - extremities(I) : returns the extremities of I; - nodes(I) : returns the nodes of I; ****************************************************************************/ namespace graph { CoxGraph::CoxGraph(const Type& x, const Rank& l) :d_type(x),d_rank(l),d_matrix(0),d_star(0) /* Initializes a Coxeter graph of type x and rank l. */ { makeCoxMatrix(d_matrix,x,d_rank); if (ERRNO) return; /* the restriction on the rank should be removed eventually */ if (l <= MEDRANK_MAX) { d_S = (LFlags)1 << d_rank-1; d_S += d_S - 1; makeStar(d_star,d_matrix,d_rank); } makeStarOps(d_starOps,d_matrix,l); return; } CoxGraph::~CoxGraph() /* Automatic destruction is enough. */ {} LFlags CoxGraph::component(LFlags I, Generator s) const /* Returns the bitmap of the connected component of s in I. */ { LFlags nf = lmask[s]; LFlags f = 0; while (nf) /* there are new elements to be considered */ { f |= nf; for (LFlags f1 = nf; f1; f1 &= f1-1) nf |= (I & d_star[firstBit(f1)]); nf &= ~f; } return f; } LFlags CoxGraph::extremities(LFlags I) const /* This function returns a bitmap of the set of points in I which are extremal in the induced graph; this means that the valency of the point is one. */ { LFlags f = 0; LFlags f1 = I; while (f1) { Generator s = firstBit(f1); if (bitCount(d_star[s]&I) == 1) /* s is an extremity */ f |= lmask[s]; f1 &= f1-1; } return f; } LFlags CoxGraph::nodes(LFlags I) const /* This function returns a bitmap of the set of points in I which are nodes for the induced graph; this means that the valency of the point is > 2. */ { LFlags f,f1; Generator s; f = 0; f1 = I; while (f1) { s = firstBit(f1); if (bitCount(d_star[s]&I) > 2) /* s is a node */ f |= lmask[s]; f1 &= f1-1; } return f; } }; /**************************************************************************** Chapter II -- Coxeter matrix functions. This section provides the functions which will fill in the Coxeter matrices in the predefined types, and those reading a matrix from a file, or reading it in interactively. These functions are private to graph.c. The following functions are provided : for filling the matrix of a finite Weyl group : - fillCoxAMatrix(m,l) : type A; - fillCoxBMatrix(m,l) : type B = C; - fillCoxDMatrix(m,l) : type D; - fillCoxEMatrix(m,l) : type E; - fillCoxFMatrix(m,l) : type F; - fillCoxGMatrix(m,l) : type G; - fillCoxHMatrix(m,l) : type H; - fillCoxIMatrix(m,l) : type I (the remaining dihedrals) (interactive); for filling the matrix of an affine Weyl group : - fillCoxaMatrix(m,l) : type a; - fillCoxbMatrix(m,l) : type b; - fillCoxcMatrix(m,l) : type c; - fillCoxdMatrix(m,l) : type d; - fillCoxeMatrix(m,l) : type e; - fillCoxfMatrix(m,l) : type f; - fillCoxgMatrix(m,l) : type g; for reading a Coxeter matrix from a file : - fillCoxXMatrix(m,l); for reading in a Coxeter matrix interactively : - fillCoxYMatrix(m,l); The functions filling in the actual data in the CoxGraph structure are : - makeCoxMatrix(m,x,l) : allocates and fills the Coxeter matrix; - makeStar(star,m,l) : allocates and fills the star array; - makeStarOps(ops,m,l) : allocates and fills the starOps array; ****************************************************************************/ namespace { void fillCoxAMatrix(CoxMatrix& m, Rank l) { for (Rank j = 1; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } return; } void fillCoxBMatrix(CoxMatrix& m, Rank l) { m[1] = 4; m[l] = 4; for (Rank j = 2; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } return; } void fillCoxDMatrix(CoxMatrix& m, Rank l) { if (l == 2) return; m[2] = 3; m[l + 2] = 3; m[2*l] = 3; m[2*l + 1] = 3; for (Rank j = 3; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } return; } void fillCoxEMatrix(CoxMatrix& m, Rank l) { m[2] = 3; m[2*l] = 3; if (l == 3) return; m[l + 3] = 3; m[2*l + 3] = 3; m[3*l + 1] = 3; m[3*l + 2] = 3; for (Rank j = 4; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } return; } void fillCoxFMatrix(CoxMatrix& m, Rank l) { for (Rank j = 1; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } m[l + 2] = 4; m[2*l + 1] = 4; return; } void fillCoxGMatrix(CoxMatrix& m) { m[1] = 6; m[2] = 6; return; } void fillCoxHMatrix(CoxMatrix& m, Rank l) { m[1] = 5; m[l] = 5; for (Rank j = 2; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } return; } void fillCoxIMatrix(CoxMatrix& m) { CoxEntry m_12; m_12 = interactive::getCoxEntry(1,2); if (ERRNO) return; m[1] = m_12; m[2] = m_12; return; } void fillCoxaMatrix(CoxMatrix& m, Rank l) { if (l == 2) { m[1] = 0; m[2] = 0; return; } for (Rank j = 1; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } m[l-1] = 3; m[(l-1)*l] = 3; return; } void fillCoxbMatrix(CoxMatrix& m, Rank l) { if (l == 3) { // go over to type c3 fillCoxcMatrix(m,3); return; } m[1] = 4; m[l] = 4; for (Rank j = 2; j < l-1; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } m[(l-3)*l + (l-1)] = 3; m[(l-1)*l + (l-3)] = 3; return; } void fillCoxcMatrix(CoxMatrix& m, Rank l) { m[1] = 4; m[l] = 4; for (Rank j = 2; j < l-1; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } m[(l-2)*l + (l-1)] = 4; m[(l-1)*l + (l-2)] = 4; return; } void fillCoxdMatrix(CoxMatrix& m, Rank l) { m[2] = 3; m[2*l] = 3; for (Rank j = 2; j < l-1; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } m[(l-3)*l + (l-1)] = 3; m[(l-1)*l + (l-3)] = 3; return; } void fillCoxeMatrix(CoxMatrix& m, Rank l) { m[2] = 3; m[2*l] = 3; m[l + 3] = 3; m[2*l + 3] = 3; m[3*l + 1] = 3; m[3*l + 2] = 3; for (Rank j = 4; j < l-1; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } switch (l) { case 5: m[l-1] = 3; m[l + (l-1)] = 3; m[(l-1)*l] = 3; m[(l-1)*l + 1] = 3; break; case 6: m[2*l + (l-1)] = 3; m[(l-1)*l + 2] = 3; break; case 7: m[l + (l-1)] = 3; m[(l-1)*l + 1] = 3; break; case 8: m[l-1] = 3; m[(l-1)*l] = 3; break; case 9: m[(l-2)*l + (l-1)] = 3; m[(l-1)*l + (l-2)] = 3; break; } return; } void fillCoxfMatrix(CoxMatrix& m, Rank l) { for (Rank j = 1; j < l; j++) { m[(j-1)*l + j] = 3; m[j*l + (j-1)] = 3; } m[l + 2] = 4; m[2*l + 1] = 4; return; } void fillCoxgMatrix(CoxMatrix& m) { m[1] = 6; m[3] = 6; m[5] = 3; m[7] = 3; return; } void fillCoxXMatrix(CoxMatrix& m, const Rank& l, const Type& t) /* Recall that in type X the type is really a string, where the name of a valid input file follows X, lying under coxeter_matrices. The program reads the first l entries of the first l lines in the file; this allows us sometimes to define a whole family of groups with a single file. NOTE : this should perhaps be completed by a recognition test, in order to renumber the generators if necessary (and then modify the matrix accordingly). For the time being, we leave it as is. */ { static String buf(0); using directories::COXMATRIX_DIR; const String& name = t.name(); buf.setLength(strlen(COXMATRIX_DIR)+1+name.length()); // one char for `\` sprintf(buf.ptr(),"%s/%s",COXMATRIX_DIR,name.ptr()+1); FILE *inputfile = fopen(buf.ptr(),"r"); for (Rank i = 0; i < l; i++) { for (Rank j = 0; j < l; j++) { /* check for EOL */ if (interactive::endOfLine(inputfile)) { Error(BAD_LINE,name.ptr()+1,l,i,j); ERRNO = ABORT; return; } m[i*l + j] = interactive::readCoxEntry(i,j,inputfile); if (ERRNO) { Error(ERRNO,i,j); ERRNO = ABORT; return; } /* check for symmetry */ if (j < i) if (m[i*l + j] != m[j*l + i]) { Error(NOT_SYMMETRIC,name.ptr()+1,&m,l,i,j); ERRNO = ABORT; return; } } /* flush remaining line of the inputfile */ char c; while((c = getc(inputfile)) != EOF) if (c == '\n') break; } fclose(inputfile); return; } void fillCoxYMatrix(CoxMatrix& m, Rank l) /* This is the type for arbitrary input, where the coxeter matrix is gotten interactively from the user. He is prompted only for entries i,j for which i < j. NOTE : this should be completed by a recognition test, in order to renumber the generators if necessary (and then modify the matrix accordingly). For the time being, we leave it as is. */ { for (Rank i = 0; i < l; i++) for (Rank j = i+1; j < l; j++) { m[i*l + j] = interactive::getCoxEntry(i+1,j+1); if (ERRNO) { Error(ERRNO); ERRNO = ERROR_WARNING; return; } m[j*l + i] = m[i*l + j]; } return; } void makeCoxMatrix(CoxMatrix& m, const Type& x, const Rank& l) /* Allocates and fills in the Coxeter matrix. In the case of type X, this includes checking the input file for correct values; in the case of type I, we need to get to get the only non-trivial entry of the matrix from the user. In the case of failure, it sets an error, and returns. */ { m.setSize(l*l); for (Ulong j = 0; j < static_cast(l*l); ++j) m[j] = 2; for (Ulong j = 0; j < l; ++j) m[j*l+j] = 1; switch (x[0]) { case 'A': fillCoxAMatrix(m,l); break; case 'B': fillCoxBMatrix(m,l); break; case 'D': fillCoxDMatrix(m,l); break; case 'E': fillCoxEMatrix(m,l); break; case 'F': fillCoxFMatrix(m,l); break; case 'G': fillCoxGMatrix(m); break; case 'H': fillCoxHMatrix(m,l); break; case 'I': fillCoxIMatrix(m); if (ERRNO) return; break; case 'a': fillCoxaMatrix(m,l); break; case 'b': fillCoxbMatrix(m,l); break; case 'c': fillCoxcMatrix(m,l); break; case 'd': fillCoxdMatrix(m,l); break; case 'e': fillCoxeMatrix(m,l); break; case 'f': fillCoxfMatrix(m,l); break; case 'g': fillCoxgMatrix(m); break; case 'X': fillCoxXMatrix(m,l,x); break; case 'Y': fillCoxYMatrix(m,l); break; } return; } void makeStar(List& star, const CoxMatrix& m, const Rank& l) /* Makes the star-array of the Coxeter graph. This is an array of l LFlags, flagging the "stars" of each generator in the Coxeter diagram. */ { star.setSize(l); for(Generator s = 0; s < l; s++) { star[s] = 0; for (Generator t = 0; t < l; t++) if ((m[s*l + t] > 2) || (m[s*l + t] == 0)) star[s] |= lmask[t]; } return; } void makeStarOps(List& ops, const CoxMatrix& m, const Rank& l) /* Makes the starOps array of the Coxeter graph. This array has an entry for each finite edge in the graph, which holds the 2-element subset corresponding to the edge. */ { /* count number of finite edges */ Ulong count = 0; for (Generator s = 0; s < l; ++s) { for (Generator t = s+1; t < l; ++t) { if ((m[s*l + t] > 2) && (m[s*l + t] != infty)) count++; } } ops.setSize(count); count = 0; for (Generator s = 0; s < l; ++s) { for (Generator t = s+1; t < l; ++t) { if ((m[s*l + t] > 2) && (m[s*l + t] != infty)) { ops[count] = lmask[s] | lmask[t]; count++; } } } return; } }; /**************************************************************************** Chapter III -- Graph analysis. This section defines various functions for the analysis of subsets of the Coxeter graph. The following functions are provided : - isAffine(G,I); - isConnected(G,I); - isCrystallographic(G,I); - isFinite(G,I); - isLoop(G,I); - isSimplyLaced(G,I); - isTree(G,I); In fact, the real work for isFinite and isAffine is provided in : - irrType(G,I) : returns the type of an irreducible subset; ****************************************************************************/ namespace graph { bool isAffine(CoxGraph& G, LFlags I) /* Returns true if the group generated by I is affine, false otherwise. Uses the classification of the graphs of affine Coxeter groups. It is assumed that I is already irreducible. */ { const Type& type = irrType(G,I); if (strchr("abcdefg",type[0])) /* group is affine */ return true; else return false; } bool isConnected(CoxGraph& G, LFlags I) /* Returns true if the graph induced on I is connected, false otherwise. */ { if (I == 0) return false; Generator s = firstBit(I); if (G.component(I,s) == I) return true; else return false; } bool isCrystallographic(CoxGraph& G, LFlags I) /* Checks if the restriction of the Coxeter graph to I is crystallographic, i.e., if the entries in the Coxeter matrix are all 2,3,4,6 or infinity. */ { for (Generator s = 0; s < G.rank(); s++) for (Generator t = s+1; t < G.rank(); t++) { switch (G.M(s,t)) { case 0: case 2: case 3: case 4: case 6: continue; default: return false; }; } return true; } bool isFinite(CoxGraph& G, LFlags I) /* Returns true if the group generated by I is finite, false otherwise. Uses the classification of the graphs of finite Coxeter groups. */ { while (I) { Generator s = firstBit(I); LFlags f = G.component(I,s); const Type& type = irrType(G,f); if (strchr("ABCDEFGHI",type[0]) == NULL) return false; I &= ~f; } return true; } bool isLoop(CoxGraph& G, LFlags I) /* Returns 1 if the graph induced on I is a loop, 0 otherwise. Uses the characterization that a loop is a connected graph for which all valencies are equal to 2. */ { if (!isConnected(G,I)) return false; for (LFlags f = I; f; f &= f-1) { Generator s = firstBit(f); if (bitCount(G.star(I,s)) != 2) return false; } return true; } bool isSimplyLaced(CoxGraph& G, LFlags I) /* Returns true if the Coxeter graph restricted to I is simply laced (i.e., all edges have label 3), false otherwise. */ { for (LFlags fs = I; fs; fs &= fs-1) { Generator s = firstBit(fs); for (LFlags ft = fs & fs-1; ft; ft &= ft-1) { Generator t = firstBit(ft); if ((G.M(s,t) == 0) || (G.M(s,t) > 3)) return false; } } return true; } bool isTree(CoxGraph& G, LFlags I) /* Returns 1 if the graph induced on I is a tree, 0 otherwise. Uses the characterization that a tree is a connected graph for which the number of edges is the number of vertices minus one. */ { if (!isConnected(G,I)) return false; unsigned edgecount = 0; for (LFlags f = I; f; f &= f-1) { Generator s = firstBit(f); edgecount += bitCount(G.star(I,s)); } edgecount /= 2; /* each edge was counted twice */ if (edgecount == (bitCount(I) - 1)) return true; else return false; } }; namespace { const Type& irrType(CoxGraph& G, LFlags I) /* Returns the type of the subgraph induced on I, if this subgraph is irreducible, finite or affine. Assumes that irreducibility has already been checked. Returns type "X" if the type is not defined. The result is returned as type, which is a safe place until the next call to irrType. */ { static Type type("X"); if (bitCount(I) == 1) { type[0] = 'A'; return type; } if (bitCount(I) == 2) { Generator s = firstBit(I); Generator t = firstBit(I & I-1); CoxEntry m = G.M(s,t); switch (m) { case 0: type[0] = 'a'; return type; case 3: type[0] = 'A'; return type; case 4: type[0] = 'B'; return type; case 5: type[0] = 'H'; return type; case 6: type[0] = 'G'; return type; default: type[0] = 'I'; return type; }; } /* from here on the rank is at least three */ if (!isTree(G,I)) /* type must be a_n */ { if (!isLoop(G,I)) /* unknown type */ return type; if (!isSimplyLaced(G,I)) /* unknown type */ return type; type[0] = 'a'; return type; } /* from here on the graph is a tree */ CoxEntry m = maxCoefficient(G,I); switch (m) { case 3: { /* simply laced : type is A, D, E, d, e if known */ LFlags fn = G.nodes(I); switch (bitCount(fn)) { case 0: /* type A */ type[0] = 'A'; return type; case 1: { /* type is D, E, e, or d5, if known */ Generator n = firstBit(G.nodes(I)); switch (bitCount(G.star(n))) { case 3: { /* type is D, E or e */ LFlags f = G.extremities(I); switch (bitCount(f & G.star(n))) /* short branches */ { case 3: /* type is D4 */ type[0] = 'D'; return type; case 2: /* type is Dn, n >= 5 */ type[0] = 'D'; return type; case 1: { /* type is E6, E7, E8, e8 or e9 */ /* trim branches by one */ LFlags J = I & ~f; f = G.extremities(J); switch (bitCount(f & G.star(n))) { case 0: /* two branches of length > 2 */ if (bitCount(I) == 8) /* type e8 */ type[0] = 'e'; return type; case 1: /* one branch of length 2 */ switch (bitCount(I)) { case 7: /* type E7 */ case 8: /* type E8 */ type[0] = 'E'; return type; case 9: /* type e9 */ type[0] = 'e'; return type; default: /* unknown type */ return type; }; case 2: /* two branches of length 2 */ if (bitCount(I) == 6) /* type E6 */ type[0] = 'E'; return type; }; } case 0: /* type has to be e7 */ if (bitCount(I) == 7) type[0] = 'e'; return type; }; } case 4: /* type is d5 */ if (bitCount(I) == 5) type[0] = 'd'; return type; default: /* unknown type */ return type; }; } case 2: { LFlags f = G.extremities(I); if (bitCount(f) > 4) /* unknown type */ return type; /* from here on each node has three branches */ LFlags J = I & ~f; f = G.extremities(J); if (f == fn) /* type d */ type[0] = 'd'; return type; } default: /* unknown type */ return type; }; } case 4: { /* type is B, F, b, c or f if known */ switch (bitCount(G.nodes(I))) { case 0: { /* graph is a string : type is B, F, c or f */ LFlags f = G.extremities(I); LFlags J = I & ~f; switch (maxCoefficient(G,J)) { case 1: case 3: { /* type is B or c */ type[0] = 'B'; Generator s = firstBit(f); Generator t = firstBit(G.star(s)); CoxEntry m1 = G.M(s,t); if (m1 == 3) return type; f &= f-1; s = firstBit(f); t = firstBit(G.star(s)); m1 = G.M(s,t); if (m1 == 4) type[0] = 'c'; return type; } case 4: /* type is F or f, if known */ switch (bitCount(I)) { case 4: /* type F4 */ type[0] = 'F'; return type; case 5: { CoxEntry m1 = minCoefficient(G,J); if (m1 == 3) /* type f5 */ type[0] = 'f'; return type; } default: /* unknown type */ return type; }; default: /* unknown type */ return type; }; } case 1: { /* type is b if known */ LFlags f = G.extremities(I); if (bitCount(f) > 3) /* more than three branches */ return type; LFlags J = I & ~f; if (!isSimplyLaced(G,J)) /* unknown type */ return type; Generator n = firstBit(G.nodes(I)); f &= G.star(n); switch (bitCount(f)) { case 2: /* exactly one long branch */ J = f | lmask[n]; if (isSimplyLaced(G,J)) /* type is b */ type[0] = 'b'; return type; case 3: /* type is b4 */ type[0] = 'b'; return type; default: /* more than one long branch */ return type; }; } default: /* unknown type */ return type; }; } case 5: { /* type must be H3 or H4 if known */ switch (bitCount(I)) { case 3: { CoxEntry m1 = minCoefficient(G,I); if (m1 == 3) type[0] = 'H'; return type; } case 4: { if (G.nodes(I)) /* graph is not a string */ return type; LFlags f = G.extremities(I); LFlags J = I & ~f; if (!isSimplyLaced(G,J)) /* unknown type */ return type; J = 0; for (; f; f &= f-1) { Generator s = firstBit(f); J |= G.star(s); } CoxEntry m1 = minCoefficient(G,J); if (m1 == 3) type[0] = 'H'; return type; } default: return type; }; break; } case 6: { /* type must be g3 if known */ switch(bitCount(I)) { case 3: { CoxEntry m1 = minCoefficient(G,I); if (m1 == 3) type[0] = 'g'; return type; } default: return type; }; } default: /* unknown type */ return type; }; return type; // unreachable } }; namespace graph { const Type& type(CoxGraph& G, LFlags I) /* Returns the type of the group generated by I as a string containing one letter for each component of I, in increasing order : A-I if the component is finite, a-g if it is affine, X otherwise. So the length of the string is the number of components of the group. Returns the empty string if I = 0. The result is returned as buf.ptr(), which is a safe place until the next call to type */ { static Type type(0); LFlags f; Generator s; type.name().setLength(G.rank()); for (Ulong j = 0; I; j++) /* run through connected components */ { s = firstBit(I); f = G.component(I,s); type[j] = (irrType(G,f))[0]; I &= ~f; } return type; } }; /**************************************************************************** Chapter IV -- Order computations. This section regroups functions for computing the order of subgroups generated by subsets of S. The functions are : - A_order(rank),B_order(rank),D_order(rank) : order functions for the infinite families; - dihedralOrder(G,I) : returns the order for dihedral groups; - extrQuotOrder(G,I,s) : returns the order of the quotient of I by I\{s}, where I is irreducible and s extremal; - finiteOrder(type,rank) : returns the order of the standard irreducible finite Coxeter groups; - order(G,I) : returns the order of the subgroup generated by I; - quotOrder(G,I,J) : returns |W_I/W_J|, assuming that J is included in I; - lastQuotOrder(type,rank) : returns the order of the privileged quotient in the given type and rank; NOTE : the return value 0 should probably be changed to overflow. ****************************************************************************/ namespace { CoxSize A_order(Rank rank) /* Returns the order of the Coxeter group of type A and rank given, if this fits into a CoxSize, 0 otherwise. Of course the answer is (rank+1)! */ { CoxSize a = 1; for (Rank j = 1; j <= rank; j++) { if (a > COXSIZE_MAX/(j+1)) return 0; a *= j+1; } return a; } CoxSize B_order(Rank rank) /* Returns the order of the Coxeter group of type B and rank given, if this fits into a CoxSize, 0 otherwise. The answer is 2^rank*(rank!) */ { CoxSize a = 2; for (Rank j = 2; j <= rank; j++) { if (a > COXSIZE_MAX/(2*j)) return 0; a *= 2*j; } return a; } CoxSize D_order(Rank rank) /* Returns the order of the Coxeter group of type D and rank given, if this fits into a CoxSize, 0 otherwise. The answer is 2^(rank-1)*(rank!). */ { CoxSize a = 24; for (Rank j = 4; j <= rank; j++) { if (a > COXSIZE_MAX/(2*j)) return 0; a *= 2*j; } return a; } CoxSize dihedralOrder(CoxGraph& G, LFlags I) /* Assuming that |I| = 2, returns the order of the subgroup generated by I. The answer is 2*m, where m=m_{s,t} is the Coxeter coefficient determined by I. */ { CoxSize m; Generator s, t; s = firstBit(I); I &= I-1; t = firstBit(I); m = (CoxSize)(G.M(s,t)); if (m > COXSIZE_MAX/2) return 0; return 2*m; } ParSize extrQuotOrder(CoxGraph& G, LFlags I, Generator s) /* Assuming I irreducible and s extremal, this function returns the order of the quotient of I by I\{s}. It is assumed that LPARNBR_MAX >= 2^31 */ { Rank l; LFlags I1; Generator s1; CoxEntry m; const Type& t = irrType(G,I); l = bitCount(I); if (l == 1) return (ParSize)2; I1 = I & ~lmask[s]; const Type& t1 = irrType(G,I1); switch (t[0]) { case 'A': return (ParSize)(l+1); case 'B': switch (t1[0]) { case 'A': /* return 2^l */ if (l == BITS(ParSize)) return 0; else return (ParSize)1 << l; case 'B': return (ParSize)(2*l); }; case 'D': switch (t1[0]) { case 'A': /* return 2^(l-1) */ return (ParSize)1 << (l-1); case 'D': return (ParSize)(2*l); }; case 'E': switch (l) { case 6: switch (t1[0]) { case 'A': return (ParSize)72; case 'D': return (ParSize)27; }; case 7: switch (t1[0]) { case 'A': return (ParSize)576; case 'D': return (ParSize)126; case 'E': return (ParSize)56; }; case 8: switch (t1[0]) { case 'A': return (ParSize)17280; case 'D': return (ParSize)2160; case 'E': return (ParSize)240; }; }; case 'F': return (ParSize)24; case 'G': return (ParSize)6; case 'H': switch (l) { case 2: return (ParSize)5; case 3: switch (t1[0]) { case 'H': return (ParSize)12; case 'A': return (ParSize)20; }; case 4: switch (t1[0]) { case 'H': return (ParSize)120; case 'A': return (ParSize)600; }; }; case 'I': I &= ~(lmask[s]); s1 = firstBit(I); m = G.M(s,s1); return (ParSize)m; default: /* group is not finite */ return 0; }; } CoxSize finiteOrder(const Type& type, const Rank& rank) /* This function returns the order of the group of the given type and rank, by dispatching it to the appropriate sub-function. It is assumed that type[0] is one of A-H. Type I is handled separately. It is assumed that the rank has been scanned so that it is >= 1 in type A, >= 2 in type B, >= 4 in type D, 6,7,8 in type E, 4 in type F, 2 in type G, 2,3,4 in type H. The returnvalue is the order of the group if this fits into a CoxSize, 0 otherwise. */ { switch (type[0]) { case 'A': return A_order(rank); case 'B': case 'C': return B_order(rank); case 'D': return D_order(rank); case 'E': switch (rank) { case 6: return static_cast(51840); case 7: return static_cast(2903040); case 8: return static_cast(696729600); }; case 'F': return static_cast(1152); case 'G': return static_cast(12); case 'H': switch (rank) { case 2: return static_cast(10); case 3: return static_cast(120); case 4: return static_cast(14400); }; default: // unreachable return 0; }; } ParSize lastQuotOrder(const Type& type, Rank rank) /* Returns the order of the privileged quotient in the given type and rank. Ther cannot be any overflow. It is assumed that the type is one of A-H. */ { switch (type[0]) { case 'A': return static_cast(rank+1); case 'B': case 'C': case 'D': return static_cast(2*rank); case 'E': switch (rank) { case 6: return static_cast(27); case 7: return static_cast(56); case 8: return static_cast(240); }; case 'F': return static_cast(24); case 'G': return static_cast(6); case 'H': switch (rank) { case 2: return static_cast(5); case 3: return static_cast(12); case 4: return static_cast(120); }; default: // unreachable return 0; }; } }; namespace graph { CoxSize order(CoxGraph& G, LFlags I) /* Returns the order of the subgroup generated by I, if this fits into a CoxSize, 0 otherwise. */ { if (I == 0) return 1; Generator s = firstBit(I); LFlags J = G.component(I,s); if (J != I) /* group is not irreducible */ { CoxSize c1 = order(G,J); CoxSize c2 = order(G,I&~J); if (c1 & c2 & (c2 > COXSIZE_MAX/c1)) /* overflow */ return 0; return c1*c2; } const Type& t = irrType(G,I); Rank l = bitCount(I); if (t[0] == 'I') return dihedralOrder(G,I); else return finiteOrder(t,l); } ParSize quotOrder(CoxGraph& G, LFlags I, LFlags J) /* Returns the number of elements of W_I/W_J, assuming that J is contained in I, that W_I is finite, and that the results does not exceed LPARNBR_MAX; returns 0 otherwise. */ { if (I == J) return 1; Generator s = firstBit(I); LFlags I1 = G.component(I,s); if (I1 != I) /* argue by induction */ { LFlags J1 = J & I1; LFlags I2 = I & ~I1; LFlags J2 = J & ~J1; ParSize c1 = quotOrder(G,I1,J1); ParSize c2 = quotOrder(G,I2,J2); if (c1 & c2 & (c2 > LPARNBR_MAX/c1)) /* overflow */ return 0; return c1*c2; } /* now I is irreducible */ const Type& type = irrType(G,I); if (strchr("ABCDEFGHI",type[0]) == NULL) /* group is infinite */ return 0; Rank l = bitCount(I); if (l == 2) /* dihedral case */ { Generator s = firstBit(I); Generator t = firstBit(G.star(I,s)); CoxEntry m = G.M(s,t); if (m == 0) /* group is infinite */ return 0; switch(bitCount(J)) { case 0: return static_cast(2*m); case 1: return static_cast(m); }; } s = lastGenerator(G,I); I1 = I & ~(lmask[s]); LFlags J1 = J & ~(lmask[s]); ParSize c1 = lastQuotOrder(type,l); ParSize c2 = quotOrder(G,I1,J1); if (c2 == 0) return 0; if ((J & lmask[s]) == 0) /* s is not in J */ goto exit; J = G.component(J,s); { ParSize q = extrQuotOrder(G,J,s); ParSize d = gcd((Ulong)c1,(Ulong)q); c1 /= d; q /= d; c2 /= q; /* now c2 must be divisible by q */ } exit: if (c2 > LPARNBR_MAX/c1) /* overflow */ return 0; return c1*c2; } }; /**************************************************************************** Chapter V -- Utility functions. This section defines various utility functions : - gcd(a,b) : yes, the classic Euclidian algorithm; - getConjugacyClasses(cl) : puts in cl the conjugacy classes of generators; - lastGenerator(G,I) : returns the last generator in the standard enumeration of I; - maxCoefficient(G,I) : returns the largest coefficient in m|I; - minCoefficient(G,I) : returns the smallest coefficient in m|I; ****************************************************************************/ namespace { Ulong gcd(Ulong a, Ulong b) /* The classic Euclidian algorithm. It is assumed that a and b are non-zero. */ { if (a < b) /* exchange a and b */ return gcd(b,a); Ulong r = a%b; while (r != 0) { a = b; b = r; r = a%b; } return b; } }; namespace graph { void getConjugacyClasses(List& cl, const CoxGraph& G) /* This function returns in cl the conjugacy classes of generators in W (i.e. the partition of S induced by the partition of W in conjugacy classes.) It is known that these are the connected components of the graph obtained by removing from the Coxeter graph all edges with even or infinite labels. */ { List odd_star(0); odd_star.setSize(G.rank()); for(Generator s = 0; s < G.rank(); ++s) { odd_star[s] = 0; for (Generator t = 0; t < G.rank(); ++t) if ((G.M(s,t)%2) && (G.M(s,t) > 1)) odd_star[s] |= lmask[t]; } Ulong c = 0; for (LFlags fS = G.supp(); fS; ++c) { LFlags nf = lmask[firstBit(fS)]; LFlags f = 0; while (nf) /* there are new elements to be considered */ { f |= nf; for (LFlags f1 = nf; f1; f1 &= f1-1) nf |= (odd_star[firstBit(f1)]); nf &= ~f; } cl.setSize(c+1); cl[c] = f; fS &= ~f; } return; } }; namespace { Generator lastGenerator(CoxGraph& G, LFlags I) /* Assuming that I is irreducible, this function returns an element in I which can be taken as a last generator in the standard enumeration. */ { Rank l = bitCount(I); if (l <= 2) return firstBit(I); /* from now on the rank is at least three */ const Type& x = irrType(G,I); LFlags f = G.extremities(I); switch (x[0]) { case 'A': return firstBit(f); case 'B': { Generator s = firstBit(f); Generator t = firstBit(G.star(I,s)); CoxEntry m = G.M(s,t); switch (m) { case 3: return s; case 4: f &= ~(lmask[s]); return firstBit(f); }; } case 'D': { Generator s = firstBit(f); Generator n = firstBit(G.nodes(I)); f &= ~(G.star(n)); if (f) return firstBit(f); else /* rank is 4 */ return s; } case 'E': { Generator n = firstBit(G.nodes(I)); f &= ~(G.star(n)); Generator s = firstBit(f); switch (l) { case 6: return s; case 7: case 8: { Generator t = firstBit(G.star(I,s)); if (lmask[t] & G.star(n)) { f &= ~(lmask[s]); return firstBit(f); } else return s; } }; } case 'F': return firstBit(f); case 'H': { Generator s = firstBit(f); Generator t = firstBit(G.star(I,s)); CoxEntry m = G.M(s,t); switch (m) { case 3: return s; case 5: f &= ~(lmask[s]); return firstBit(f); }; } case 'a': return firstBit(I); case 'b': { Generator s = firstBit(f); Generator t = firstBit(G.star(I,s)); CoxEntry m = G.M(s,t); switch (m) { case 3: return s; case 4: f &= ~(lmask[s]); return firstBit(f); }; } case 'c': return firstBit(f); case 'd': return firstBit(f); case 'e': { switch (l) { case 7: return firstBit(f); case 8: { Generator n = firstBit(G.nodes(I)); f &= ~(G.star(n)); return firstBit(f); } case 9: { Generator n = firstBit(G.nodes(I)); f &= ~(G.star(n)); Generator s = firstBit(f); Generator t = firstBit(G.star(I,s)); if (lmask[t] & G.star(n)) { f &= ~(lmask[s]); return firstBit(f); } else return s; } }; } case 'f': { Generator s = firstBit(f); LFlags I1 = I & ~(lmask[s]); switch ((irrType(G,I1))[0]) { case 'B': f &= ~(lmask[s]); return firstBit(f); case 'F': return s; }; } case 'g': { Generator s = firstBit(f); Generator t = firstBit(G.star(I,s)); CoxEntry m = G.M(s,t); switch (m) { case 3: return s; case 6: f &= ~(lmask[s]); return firstBit(f); }; } default: return lastBit(I); }; } CoxEntry maxCoefficient(CoxGraph& G, LFlags I) /* Returns the maximal coefficient in the Coxeter matrix restricted to I (we assume that I is not empty). */ { if (bitCount(I) == 1) return 1; CoxEntry m = 2; for (LFlags fs = I; fs; fs &= fs-1) { Generator s = firstBit(fs); for (LFlags ft = fs&G.star(s); ft; ft &= ft-1) { Generator t = firstBit(ft); if (G.M(s,t) == 0) return 0; if (G.M(s,t) > m) m = G.M(s,t); } } return m; } CoxEntry minCoefficient(CoxGraph& G, LFlags I) /* Returns the minimal coefficient > 2 in the Coxeter matrix restricted to I, if there is such; otherwise, if |I| > 1, returns 2; otherwise, returns 1. It is assumed that I is not empty. */ { if (bitCount(I) == 1) return 1; CoxEntry m = maxCoefficient(G,I); if (m == 2) return 2; for (Generator s = 0; s < G.rank(); s++) for (LFlags f = I&G.star(s); f; f &= f-1) { Generator t = firstBit(f); if ((G.M(s,t) != 0) && (G.M(s,t) < m)) m = G.M(s,t); } return m; } }; positivity_final/graph.h0000600000175000017500000000644710011171251017104 0ustar duclouxducloux00000000000000/* This is graph.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /* type definitions */ #ifndef GRAPH_H /* guarantee single inclusion */ #define GRAPH_H #include "globals.h" #include "list.h" namespace graph { using namespace globals; using namespace list; }; /* type declarations */ namespace graph { class CoxGraph; typedef unsigned short CoxEntry; typedef List CoxMatrix; } #include "bits.h" #include "coxtypes.h" #include "memory.h" namespace graph { using namespace bits; using namespace coxtypes; using namespace memory; }; /* constants */ namespace graph { const Ulong SBITMAP_MAX = RANK_MAX/CHAR_BIT + (bool)(RANK_MAX%CHAR_BIT); /* a CoxNbr should hold at least 2 COXENTRY_MAX elements */ static const CoxEntry COXENTRY_MAX = 32763; static const CoxEntry undef_coxentry = USHRT_MAX; static const CoxEntry infty = 0; }; /******** function declarations **********************************************/ #include "type.h" namespace graph { using namespace type; }; namespace graph { void getConjugacyClasses(List& cl, const CoxGraph& G); bool isAffine(CoxGraph& G, LFlags I); bool isConnected(CoxGraph& G, LFlags I); bool isCrystallographic(CoxGraph& G, LFlags I); bool isFinite(CoxGraph& G, LFlags I); bool isLoop(CoxGraph& G, LFlags I); bool isSimplyLaced(CoxGraph& G, LFlags I); bool isTree(CoxGraph& G, LFlags I); CoxSize order(CoxGraph& G, LFlags I); ParSize quotOrder(CoxGraph& G, LFlags I, LFlags J); Generator *standardEnumeration(CoxGraph& G, LFlags I); const Type& type(CoxGraph& G, LFlags I); }; /* type definitions */ class graph::CoxGraph { private: Type d_type; Rank d_rank; CoxMatrix d_matrix; LFlags d_S; List d_star; List d_starOps; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(CoxGraph));} CoxGraph(const Type& x, const Rank& l); ~CoxGraph(); /* accessors */ LFlags component(LFlags I,Generator s) const; LFlags extremities(LFlags I) const; CoxEntry M(Generator s, Generator t) const; /* inlined */ LFlags nodes(LFlags I) const; Rank rank() const; /* inlined */ LFlags supp() const; /* inlined */ LFlags star(Generator s) const; /* inlined */ LFlags star(LFlags I, Generator s) const; /* inlined */ const List& starOps() const; /* inlined */ const Type& type() const; /* inlined */ }; /******** inline definitions **********************************************/ namespace graph { inline CoxEntry CoxGraph::M(Generator s, Generator t) const {return(d_matrix[s*d_rank + t]);} inline Rank CoxGraph::rank() const {return d_rank;} inline LFlags CoxGraph::supp() const {return d_S;} inline LFlags CoxGraph::star(Generator s) const {return(d_star[s]);} inline LFlags CoxGraph::star(LFlags I, Generator s) const {return(d_star[s]&I);} inline const List& CoxGraph::starOps() const {return d_starOps;} inline const Type& CoxGraph::type() const {return d_type;} }; #endif positivity_final/hecke.cpp0000600000175000017500000000000010011171251017370 0ustar duclouxducloux00000000000000positivity_final/hecke.h0000600000175000017500000000612710011171251017055 0ustar duclouxducloux00000000000000/* This is hecke.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef HECKE_H /* guard against multiple inclusions */ #define HECKE_H #include "globals.h" #include "list.h" /******** type declarations *************************************************/ namespace hecke { template class HeckeMonomial; template struct NFCompare; template class HeckeIterator; template class ToCoxNbr; }; /******** function declarations *********************************************/ #include "interface.h" #include "schubert.h" namespace hecke { using namespace interface; using namespace schubert; }; namespace hecke { template void append(String& str, const HeckeMonomial

& m, const SchubertContext& p, const Interface& I); template void prettyPrint(FILE* file, const List >& h, const Permutation& a, const SchubertContext& p, const Interface& I, const Length& l, const Ulong &ls = LINESIZE); template void printBasis(FILE* f, const List >& h, const Interface& I); template void singularStratification(List >& hs, const List >& h, const SchubertContext& p); }; /******** type definitions **************************************************/ namespace hecke { template class HeckeMonomial { private: CoxNbr d_x; const P* d_pol; public: typedef P PolType; /* constructors and destructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(HeckeMonomial));} HeckeMonomial() {}; HeckeMonomial(const CoxNbr& x, const P* pol); ~HeckeMonomial(); /* accessors */ bool operator> (const HeckeMonomial& m); const P& pol() const; /* inlined */ CoxNbr x() const; /* inlined */ /* manipulators */ void setData(const CoxNbr& x, const P* pol); }; template class ToCoxNbr { private: const List >* d_h; public: ToCoxNbr(const List >* h):d_h(h) {}; ~ToCoxNbr() {}; CoxNbr operator() (const Ulong& j) {return (*d_h)[j].x();} }; template struct NFCompare { const SchubertContext& p; const Permutation& order; NFCompare(const SchubertContext& q, const Permutation& generator_ordering) :p(q),order(generator_ordering) {}; ~NFCompare() {}; bool operator()(const HeckeMonomial

& a, const HeckeMonomial

& b) const {return shortLexOrder(p,a.x(),b.x(),order);} }; }; /******** inline definitions ************************************************/ namespace hecke { template inline bool HeckeMonomial

::operator> (const HeckeMonomial

& m) {return d_x > m.d_x;} template inline const P& HeckeMonomial

::pol() const {return *d_pol;} template inline CoxNbr HeckeMonomial

::x() const {return d_x;} template inline void HeckeMonomial

::setData(const CoxNbr& x, const P* pol) {d_x = x; d_pol = pol;} }; #include "hecke.hpp" #endif positivity_final/hecke.hpp0000600000175000017500000002175110011171251017415 0ustar duclouxducloux00000000000000/* This is hecke.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "polynomials.h" namespace hecke { using namespace polynomials; }; /***************************************************************************** This module provides some definitions and functions (mostly output-oriented) for Hecke algebra elements. We have refrained in this program from actually implementing the Hecke algebra structure, which could easily lead to immense computations. Our main purpose is to have convenient containers for communicating data. (For this reason also our coefficients are the ordinary k-l polynomials in q, instead of Laurent polynomials in q^{1/2}, as they should be.) Things are written as templates because various types of coefficients could (and do, in this program) occur. ******************************************************************************/ namespace { using namespace hecke; template struct PPtrF { typedef const P* valueType; valueType operator() (const HeckeMonomial

& m) {return &m.pol();} }; template void appendStar(String& str, const HeckeMonomial

& m, const SchubertContext& p, const Length& l); template Ulong maxLength(const List >& h, const SchubertContext& p, const Interface& I, const Length& l); template void oneColumnPrint(FILE* file, const List >& h, const Permutation& a, const SchubertContext& p, const Interface& I, const Length& l, const Ulong& ls); template void twoColumnPrint(FILE* file, const List >& h, const Permutation&a, const SchubertContext& p, const Interface& I, const Length& l, const Ulong& ls); }; /***************************************************************************** Chapter II -- The HeckeMonomial class. HeckeMonomial's are simply building blocks for HeckeElt's. They contain a context number and a polynomial reference. The following functions are defined : - constructors and destructors : - HeckeMonomial(x,pol); - ~HeckeMonomial(); - accessors : - manipulators : - order(c) : orders according to c; *****************************************************************************/ namespace hecke { template HeckeMonomial

::HeckeMonomial(const CoxNbr& x, const P* pol) :d_x(x), d_pol(pol) {} template HeckeMonomial

::~HeckeMonomial() /* Automatic destruction is enough. */ {} }; /***************************************************************************** Chapter III -- Utilities. This section defines some utility functions declared in hecke.h : - append(str,m,p,I) : appends m to str using I; - appendStar(str,m,p,l) : appends a star to str if there is a mu-coefficient; - maxLength(h,p,I,l) : computes the maximal length of an output line; - oneColumnPrint(h,p,I,l,ls) : does one-column output; - prettyPrint(f,h,I,l) : pretty-prints h on f, using I; - singularStratification(hs,h,p) : puts in hs the singular stratification of h; - singularLocus(hs,h,p) : puts in hs the rational singular locus of h; - twoColumnPrint(h,p,I,l,ls) : does two-column output; *****************************************************************************/ namespace hecke { template void append(String& str, const HeckeMonomial

& m, const SchubertContext& p, const Interface& I) /* Outputs m to str. */ { p.append(str,m.x(),I); io::append(str," : "); polynomials::append(str,m.pol(),"q"); return; } }; namespace { template void appendStar(String& str, const HeckeMonomial

& m, const SchubertContext& p, const Length& l) { Length lx = p.length(m.x()); if (static_cast(2*m.pol().deg()) == static_cast(l-lx-1)) append(str," *"); return; } template Ulong maxLength(const List >& h, const SchubertContext& p, const Interface& I, const Length& l) /* Returns the length of the longest line that would be printed out by oneColumnPrint(file,h,I,l). This is a preliminary to prettyprinting. */ { static String buf(0); Ulong maxl = 0; for (Ulong j = 0; j < h.size(); ++j) { reset(buf); const HeckeMonomial

& m = h[j]; hecke::append(buf,m,p,I); appendStar(buf,m,p,l); if (maxl < buf.length()) maxl = buf.length(); } return maxl; } template void oneColumnPrint(FILE* file, const List >& h, const Permutation& a, const SchubertContext& p, const Interface& I, const Length& l, const Ulong& ls) /* This function prints out the row in one-column format, trying to fold long lines decently. The width of the column is given by ls. */ { static String buf(0); for (Ulong j = 0; j < h.size(); ++j) { reset(buf); hecke::append(buf,h[a[j]],p,I); appendStar(buf,h[a[j]],p,l); foldLine(file,buf,ls,4,"+"); fprintf(file,"\n"); } } }; namespace hecke { template void prettyPrint(FILE* file, const List >& h, const Permutation& a, const SchubertContext& p, const Interface& I, const Length& l, const Ulong& ls) /* This function does the prettyprinting of h to the file. The formatting of the output is optimized for screen viewing. This means that if two entries fit on a line, we will do two-column output. Otherwise, we do one-column output, and moreover we try to fold long lines decently. The parameter l is needed to determine the non-zero mu-coefficients. */ { static String buf(0); Ulong maxl = maxLength(h,p,I,l); Ulong hl = (ls-1)/2; if (maxl > hl) return oneColumnPrint(file,h,a,p,I,l,ls); else return twoColumnPrint(file,h,a,p,I,l,ls); return; } template void singularStratification(List >& hs, const List >& h, const SchubertContext& p) /* This function extracts the "rational singular stratification". By this we mean that we sort by Kazhdan-Lusztig polynomials, and then consider maximal elements (for the Bruhat ordering) in each class. Geometrically, when the Bruhat ordering comes from the stratification of a Schubert variety cl(X_y), and the row is the extremal row for y, this means that we are looking at a version of "equisingularity" (the Kazhdan-Lusztig polynomial P_{x,y} being a measure of the failure of smoothness along the subvariety X_x), and taking maximal elements amounts to taking components of the equisingular locus. Note that as P_{x,y} is constant on each orbit in [e,y] under the descent set of y, these components always correspond to extremal elements. This is the set of data that has been popularized by Goresky in the files on his website. It is printed out in printRow. Note that from Irving (Ann. ENS ...) it is known that P_{z,y} <= P_{x,y} coefficientwise when x <= z, so P_{x,y} is a decreasing function of x, in the case of finite Weyl groups; presumably this is also known for general crystallographic Coxeter groups (= Weyl groups of Kac-Moody algebras). It is assumed that row is sorted in ShortLex order. The row is also returned sorted in ShortLex order. */ { /* sort row by kl-polynomial */ PPtrF

f; Partition pi(h.begin(),h.end(),f); /* find maximal elements in each class */ Ulong count = 0; for (PartitionIterator i(pi); i; ++i) { Ulong m = i()[0]; if (h[m].pol().deg() == 0) // polynomial is one continue; ToCoxNbr

f(&h); List c(i().begin(),i().end(),f); List a(0); extractMaximals(p,c,a); hs.setSize(count+a.size()); for (Ulong j = 0; j < a.size(); ++j) hs[count+j] = h[i()[a[j]]]; count += a.size(); } return; } }; namespace { template void twoColumnPrint(FILE* file, const List >& h, const Permutation& a, const SchubertContext& p, const Interface& I, const Length& l, const Ulong& ls) /* This function prints out the row in two-column format, on lines of length ls. It is assumed that it has been checked (using maxLength for instance) that the maximum size of an output line in print(file,kl,row) is at most (ls-1)/2 (so that there is room for at least one unit of whitespace in-between columns.) */ { static String buf(0); Ulong hl = (ls-1)/2; /* width of output column */ Ulong fl = h.size()/2; /* number of full lines */ Ulong i = 0; for (Ulong j = 0; j < fl; ++j) { /* print out a full line */ reset(buf); hecke::append(buf,h[a[i]],p,I); appendStar(buf,h[a[i]],p,l); pad(buf,ls-hl); i++; hecke::append(buf,h[a[i]],p,I); appendStar(buf,h[a[i]],p,l); i++; print(file,buf); fprintf(file,"\n"); } if (h.size()%2) { /* print out a half line */ reset(buf); hecke::append(buf,h[a[i]],p,I); appendStar(buf,h[a[i]],p,l); print(file,buf); fprintf(file,"\n"); } return; } }; positivity_final/help.cpp0000600000175000017500000003414210011171251017257 0ustar duclouxducloux00000000000000/* This is help.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "help.h" #include "commands.h" #include "directories.h" #include "io.h" namespace help { using namespace directories; using namespace io; }; /************************************************************************* Chapter I : help functions for the modes of the program These are the functions invoked upon entry into help mode from the various modes of the program : - main_help : help entry from the main mode; - interface_help : help entry from the interface mode; - interface::in_help : help entry from the interface::in mode; - interface::out_help : help entry from the interface::out mode; - uneq_help : help entry for the uneq mode; *************************************************************************/ namespace help { void main_help() { using namespace commands; printFile(stderr,"main.help1",MESSAGE_DIR); printCommands(stderr,mainCommandTree()->helpMode()); printFile(stderr,"main.help2",MESSAGE_DIR); return; } void interface_help() { using namespace commands; printFile(stderr,"interface_m.help1",MESSAGE_DIR); printCommands(stderr,interfaceCommandTree()->helpMode()); printFile(stderr,"interface_m.help2",MESSAGE_DIR); return; } namespace interface { void in_help() { using namespace commands; printFile(stderr,"interface/in_m.help1",MESSAGE_DIR); printCommands(stderr,commands::interface::inCommandTree()->helpMode()); printFile(stderr,"interface/in_m.help2",MESSAGE_DIR); return; } void out_help() { using namespace commands; printFile(stderr,"interface/out_m.help1",MESSAGE_DIR); printCommands(stderr,commands::interface::outCommandTree()->helpMode()); printFile(stderr,"interface/out_m.help2",MESSAGE_DIR); return; } }; void uneq_help() { using namespace commands; printFile(stderr,"uneq.help1",MESSAGE_DIR); printCommands(stderr,uneqCommandTree()->helpMode()); printFile(stderr,"uneq.help2",MESSAGE_DIR); return; } }; /************************************************************************* Chapter II : help functions for the commands of the program These are the functions invoked upon typing various commands in help mode. - betti_h() : help message for the "betti" command; - coatoms_h : help message for the "coatoms" command; - compute_h : help message for the "compute" command; - cr_h : help message for the carriage return; - default_h : the function executed when there is no help; - descent_h : help message for the "descent" command; - duflo_h : help message for the "duflo" command; - extremals_h : help message for the "extremals" command; - fullcontext_h : help message for the "fullcontext" command; - help_h : help message for the "help" command; - ihbetti_h() : help message for the "ohbetti" command; - inorder_h : help message for the "inorder" command; - input_h : explains input conventions; - interface_h : help message for the "interface" command; - intro_h : help for new users; - invpol_h : help message for the "invpol" command; - klbasis_h : help message for the "klbasis" command; - lcorder_h : help message for the "lcorder" command; - lcells_h : help message for the "lcells" command; - lcwgraphs_h : help message for the "lcwgraphs" command; - lrcorder_h : help message for the "lrcorder" command; - lrcells_h : help message for the "lrcells" command; - lrcwgraphs_h : help message for the "lrcwgraphs" command; - lrwgraph : help message for the "lwgraph" command; - lwgraph : help message for the "lwgraph" command; - mu_h : help message for the "mu" command; - pol_h : help message for the "pol" command; - q_h : help message for the "q" command; - qq_h : help message for the "qq" command; - rank_h : help message for the "rank" command; - rcorder_h : help message for the "rcorder" command; - rcells_h : help message for the "rcells" command; - rcwgraphs_h : help message for the "rcwgraphs" command; - rwgraph : help message for the "lwgraph" command; - show_h : help message for the "show" command; - slocus_h : help message for the "slocus" command; - sstratification_h : help message for the "sstratification" command; - type_h : help message for the "type" command; - uneq_h : help message for the "uneq" command; In uneq mode : - klbasis_h : help message for the "klbasis" command; - lcorder_h : help message for the "lcorder" command; - lcells_h : help message for the "lcells" command; - lrcorder_h : help message for the "lrcorder" command; - lrcells_h : help message for the "lrcells" command; - mu_h : help message for the "mu" command; - pol_h : help message for the "pol" command; - rcells_h : help message for the "rcells" command; - rcorder_h : help message for the "rcorder" command; In interface mode : - bourbaki_h : help message for the "bourbaki" command; - default_h : help message for the "default" command; - gap_h : help message for the "gap" command; - in_h : help message for the "in" command; - ordering_h : help message for the "ordering" command; - out_h : help message for the "out" command; - permutation_h : help message for the "permutation" command; - terse_h : help message for the "terse" command; in in or out modes : - abort_h : help message for the "abort" command; - alphabetic_h : help message for the "alphabetic" command; - bourbaki_h : help message for the "bourbaki" command; - decimal_h : help message for the "decimal" command; - default_h : help message for the "default" command; - gap_h : help message for the "gap" command; - hexadecimal_h : help message for the "hexadecimal" command; - permutation_h : help message for the "permutation" command; - postfix_h : help message for the "postfix" command; - prefix_h : help message for the "prefix" command; - separator_h : help message for the "separator" command; - symbol_h : help message for the "symbol" command; - terse_h : help message for the "terse" command; *************************************************************************/ namespace help { void betti_h() { printFile(stderr,"betti.help",MESSAGE_DIR); return; } void coatoms_h() { printFile(stderr,"compute.help",MESSAGE_DIR); return; } void compute_h() { printFile(stderr,"coatoms.help",MESSAGE_DIR); return; } void cr_h() { printFile(stderr,"cr.help",MESSAGE_DIR); return; } void default_h() { printFile(stderr,"default.help",MESSAGE_DIR); return; } void descent_h() { printFile(stderr,"descent.help",MESSAGE_DIR); return; } void duflo_h() { printFile(stderr,"duflo.help",MESSAGE_DIR); return; } void extremals_h() { printFile(stderr,"extremals.help",MESSAGE_DIR); return; } void fullcontext_h() { printFile(stderr,"fullcontext.help",MESSAGE_DIR); return; } void help_h() { printFile(stderr,"help.help",MESSAGE_DIR); return; } void ihbetti_h() { printFile(stderr,"ihbetti.help",MESSAGE_DIR); return; } void inorder_h() { printFile(stderr,"inorder.help",MESSAGE_DIR); return; } void input_h() { printFile(stderr,"input.help",MESSAGE_DIR); return; } void interface_h() { using namespace commands; printFile(stderr,"interface.help",MESSAGE_DIR); printCommands(stderr,interfaceCommandTree()->helpMode()); fprintf(stderr,"\n"); return; } void intro_h() { using namespace commands; printFile(stderr,"empty_m.help1",MESSAGE_DIR); printCommands(stderr,mainCommandTree()->helpMode()); printFile(stderr,"empty_m.help2",MESSAGE_DIR); return; } void invpol_h() { printFile(stderr,"invpol.help",MESSAGE_DIR); return; } void klbasis_h() { printFile(stderr,"klbasis.help",MESSAGE_DIR); return; } void lcorder_h() { printFile(stderr,"lcorder.help",MESSAGE_DIR); return; } void lcells_h() { printFile(stderr,"lcells.help",MESSAGE_DIR); return; } void lcwgraphs_h() { printFile(stderr,"lcwgraphs.help",MESSAGE_DIR); return; } void lrcorder_h() { printFile(stderr,"lrcorder.help",MESSAGE_DIR); return; } void lrcells_h() { printFile(stderr,"lrcells.help",MESSAGE_DIR); return; } void lrcwgraphs_h() { printFile(stderr,"lrcwgraphs.help",MESSAGE_DIR); return; } void lrwgraph_h() { printFile(stderr,"lrwgraph.help",MESSAGE_DIR); return; } void lwgraph_h() { printFile(stderr,"lwgraph.help",MESSAGE_DIR); return; } void matrix_h() { printFile(stderr,"matrix.help",MESSAGE_DIR); return; } void mu_h() { printFile(stderr,"mu.help",MESSAGE_DIR); return; } void pol_h() { printFile(stderr,"pol.help",MESSAGE_DIR); return; } void rwgraph_h() { printFile(stderr,"rwgraph.help",MESSAGE_DIR); return; } void q_h() /* Help function for the "q" command. In fact, this is executed when q is called in a mode where it is turned off. */ { printFile(stderr,"q.help",MESSAGE_DIR); return; } void qq_h() { printFile(stderr,"qq.help",MESSAGE_DIR); return; } void rank_h() { printFile(stderr,"rank.help",MESSAGE_DIR); return; } void rcorder_h() { printFile(stderr,"rcorder.help",MESSAGE_DIR); return; } void rcells_h() { printFile(stderr,"rcells.help",MESSAGE_DIR); return; } void rcwgraphs_h() { printFile(stderr,"rcwgraphs.help",MESSAGE_DIR); return; } void schubert_h() { printFile(stderr,"schubert.help",MESSAGE_DIR); return; } void show_h() { printFile(stderr,"show.help",MESSAGE_DIR); return; } void showmu_h() { printFile(stderr,"showmu.help",MESSAGE_DIR); return; } void slocus_h() { printFile(stderr,"slocus.help",MESSAGE_DIR); return; } void sstratification_h() { printFile(stderr,"sstratification.help",MESSAGE_DIR); return; } void type_h() { printFile(stderr,"type.help",MESSAGE_DIR); return; } void uneq_h() { printFile(stderr,"uneq.help",MESSAGE_DIR); return; } namespace uneq { void klbasis_h() { printFile(stderr,"uneq/klbasis.help",MESSAGE_DIR); return; } void lcorder_h() { printFile(stderr,"uneq/lcorder.help",MESSAGE_DIR); return; } void lcells_h() { printFile(stderr,"uneq/lcells.help",MESSAGE_DIR); return; } void lrcorder_h() { printFile(stderr,"uneq/lrcorder.help",MESSAGE_DIR); return; } void lrcells_h() { printFile(stderr,"uneq/lrcells.help",MESSAGE_DIR); return; } void mu_h() { printFile(stderr,"uneq/mu.help",MESSAGE_DIR); return; } void pol_h() { printFile(stderr,"uneq/pol.help",MESSAGE_DIR); return; } void rcells_h() { printFile(stderr,"uneq/rcells.help",MESSAGE_DIR); return; } void rcorder_h() { printFile(stderr,"uneq/rcorder.help",MESSAGE_DIR); return; } }; namespace interface { void abort_h() { printFile(stderr,"interface/abort.help",MESSAGE_DIR); return; } void alphabetic_h() { printFile(stderr,"interface/alphabetic.help",MESSAGE_DIR); return; } void bourbaki_h() { printFile(stderr,"interface/bourbaki.help",MESSAGE_DIR); return; } void decimal_h() { printFile(stderr,"interface/decimal.help",MESSAGE_DIR); return; } void gap_h() { printFile(stderr,"interface/gap.help",MESSAGE_DIR); return; } void default_h() { printFile(stderr,"interface/default.help",MESSAGE_DIR); return; } void hexadecimal_h() { printFile(stderr,"interface/hexadecimal.help",MESSAGE_DIR); return; } void in_h () { printFile(stderr,"interface/in.help",MESSAGE_DIR); return; } void ordering_h() { printFile(stderr,"interface/ordering.help",MESSAGE_DIR); return; } void out_h() { printFile(stderr,"interface/out.help",MESSAGE_DIR); return; } void permutation_h() { printFile(stderr,"interface/permutation.help",MESSAGE_DIR); return; } void terse_h() { printFile(stderr,"interface/terse.help",MESSAGE_DIR); return; } void in::alphabetic_h() { printFile(stderr,"interface/in/alphabetic.help",MESSAGE_DIR); return; } void in::bourbaki_h() { printFile(stderr,"interface/in/bourbaki.help",MESSAGE_DIR); return; } void in::decimal_h() { printFile(stderr,"interface/in/decimal.help",MESSAGE_DIR); return; } void in::default_h() { printFile(stderr,"interface/in/default.help",MESSAGE_DIR); return; } void in::gap_h() { printFile(stderr,"interface/in/gap.help",MESSAGE_DIR); return; } void in::hexadecimal_h() { printFile(stderr,"interface/in/hexadecimal.help",MESSAGE_DIR); return; } void in::permutation_h() { printFile(stderr,"interface/in/permutation.help",MESSAGE_DIR); return; } void in::postfix_h() { printFile(stderr,"interface/in/postfix.help",MESSAGE_DIR); return; } void in::prefix_h() { printFile(stderr,"interface/in/prefix.help",MESSAGE_DIR); return; } void in::separator_h() { printFile(stderr,"interface/in/separator.help",MESSAGE_DIR); return; } void in::symbol_h() { printFile(stderr,"interface/in/symbol.help",MESSAGE_DIR); return; } void in::terse_h() { printFile(stderr,"interface/in/terse.help",MESSAGE_DIR); return; } void out::alphabetic_h() { printFile(stderr,"interface/out/alphabetic.help",MESSAGE_DIR); return; } void out::bourbaki_h() { printFile(stderr,"interface/out/bourbaki.help",MESSAGE_DIR); return; } void out::decimal_h() { printFile(stderr,"interface/out/decimal.help",MESSAGE_DIR); return; } void out::default_h() { printFile(stderr,"interface/out/default.help",MESSAGE_DIR); return; } void out::gap_h() { printFile(stderr,"interface/out/gap.help",MESSAGE_DIR); return; } void out::hexadecimal_h() { printFile(stderr,"interface/out/hexadecimal.help",MESSAGE_DIR); return; } void out::permutation_h() { printFile(stderr,"interface/out/permutation.help",MESSAGE_DIR); return; } void out::postfix_h() { printFile(stderr,"interface/out/postfix.help",MESSAGE_DIR); return; } void out::prefix_h() { printFile(stderr,"interface/out/prefix.help",MESSAGE_DIR); return; } void out::separator_h() { printFile(stderr,"interface/out/separator.help",MESSAGE_DIR); return; } void out::symbol_h() { printFile(stderr,"interface/out/symbol.help",MESSAGE_DIR); return; } void out::terse_h() { printFile(stderr,"interface/out/terse.help",MESSAGE_DIR); return; } }; }; positivity_final/help.h0000600000175000017500000000457610011171251016734 0ustar duclouxducloux00000000000000/* This is help.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef HELP_H /* guard against multiple inclusions */ #define HELP_H #include "globals.h" namespace help { using namespace globals; }; namespace help { /* modes */ void main_help(); void interface_help(); void uneq_help(); /* commands */ void betti_h(); void coatoms_h(); void compute_h(); void cr_h(); void default_h(); void descent_h(); void duflo_h(); void extremals_h(); void fullcontext_h(); void help_h(); void ihbetti_h(); void inorder_h(); void interface_h(); void input_h(); void intro_h(); void invpol_h(); void klbasis_h(); void lcorder_h(); void lcells_h(); void lcwgraphs_h(); void lrcorder_h(); void lrcells_h(); void lrcwgraphs_h(); void lrwgraph_h(); void lwgraph_h(); void matrix_h(); void mu_h(); void ordering_h(); void pol_h(); void q_h(); void qq_h(); void rank_h(); void rcorder_h(); void rcells_h(); void rcwgraphs_h(); void rwgraph_h(); void schubert_h(); void show_h(); void showmu_h(); void slocus_h(); void sstratification_h(); void type_h(); void uneq_h(); namespace uneq{ void klbasis_h(); void lcorder_h(); void lrcorder_h(); void lcells_h(); void lrcells_h(); void mu_h(); void pol_h(); void rcells_h(); void rcorder_h(); }; /* special modes */ namespace interface { void abort_h(); void alphabetic_h(); void bourbaki_h(); void decimal_h(); void default_h(); void gap_h(); void hexadecimal_h(); void in_h (); void ordering_h(); void out_h (); void permutation_h(); void in_help (); void out_help (); void terse_h(); namespace in { void alphabetic_h(); void bourbaki_h(); void decimal_h(); void default_h(); void gap_h(); void hexadecimal_h(); void permutation_h(); void postfix_h(); void prefix_h(); void separator_h(); void symbol_h(); void terse_h(); }; namespace out { void alphabetic_h(); void bourbaki_h(); void decimal_h(); void default_h(); void gap_h(); void hexadecimal_h(); void permutation_h(); void postfix_h(); void prefix_h(); void separator_h(); void symbol_h(); void terse_h(); }; } }; #endif positivity_final/interactive.cpp0000600000175000017500000007450710012717421020663 0ustar duclouxducloux00000000000000/* This is interactive.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include #include "interactive.h" #include "affine.h" #include "automata.h" #include "directories.h" #include "error.h" #include "fcoxgroup.h" #include "general.h" #include "interface.h" #include "io.h" #include "type.h" #include "typeA.h" namespace interactive { using namespace affine; using namespace automata; using namespace error; using namespace fcoxgroup; using namespace general; using namespace io; using namespace type; using namespace typeA; }; /**************************************************************************** This module regroups code for the interaction with the user via the terminal. Basically, functions for getting input in a safe and pleasant (for the user, not the programmer!) way, and for checking the input carefully. At the level of the Coxeter matrix, we want to make extra sure that no wrong data is entered. ****************************************************************************/ /* local variables */ namespace { using namespace interactive; const Letter generator_type = 0; }; /******** local declarations ************************************************/ namespace { void checkCoxElement(CoxGroup *W, CoxWord g); void checkCoxEntry(Rank i, Rank j, Ulong m); void checkFilename(char *s); void checkLength(const long& l); void checkRank(const Rank& l, const Type& type); void checkType(String& buf); void getCoxFileName(String& buf); Ulong parse(const Interface& I, Generator &s, const String& line); Ulong parse(const Interface& I, Generator &s, const String& line, const LFlags& f); void printADiagram(FILE* file, const CoxGroup* W); void printBDiagram(FILE* file, const CoxGroup* W); void printDDiagram(FILE* file, const CoxGroup* W); void printEDiagram(FILE* file, const CoxGroup* W); void printFDiagram(FILE* file, const CoxGroup* W); void printGDiagram(FILE* file, const CoxGroup* W); void printHDiagram(FILE* file, const CoxGroup* W); void printIDiagram(FILE* file, const CoxGroup* W); }; /**************************************************************************** Chapter I -- The OutputFile class. This class is a little convenience made possible by C++ : it will automatically ask the user for a filename when the file is created, and more importantly, close the file for him when it gets out of use. C++ magic! ****************************************************************************/ namespace interactive { OutputFile::OutputFile() { static String buf(0); printf("Name an output file (hit return for stdout):\n"); interactive::getInput(stdin,buf); if (buf[0] == '\0') d_file = stdout; else d_file = fopen(buf.ptr(),"w"); } OutputFile::~OutputFile() { if (d_file != stdout) fclose(d_file); } }; /**************************************************************************** Chapter II -- Input functions. This chapter contains code to get data interactively from the user. The following functions are provided : - allocCoxGroup() : allocates a new coxgroup; - allocCoxGroup(x) : allocates a new coxgroup of type x; - getCoxEntry(i,j) : gets a coxeter matrix entry interactively from the user. Used in type I, and when the coxeter matrix is input interactively (type Y); - getCoxFileName(s) : gets a filename from the user, presumably containing the data for the coxeter matrix; - getCoxWord(W) : gets a coxword from the user; - getGenerator(W) : gets a generator from the user; - getLength(kl) : gets lengths for unequal parameters; - getRank(W) : gets the rank of the Coxeter group; - getType() : gets a type from the user; - readCoxEntry(i,j,inputfile) : reads a coxeter entry from an input file; ****************************************************************************/ namespace interactive { CoxGroup* allocCoxGroup() /* This function gets a type from the user, and allocates a CoxGroup of that type. */ { const Type& x = getType(); if (ERRNO) return 0; return allocCoxGroup(x); } CoxGroup* allocCoxGroup(const Type& x) /* This function gets a rank from the user, and allocates a CoxGroup of that rank and the given type. */ { Rank l = getRank(x); if (ERRNO) return 0; return coxeterGroup(x,l); } CoxGroup* coxeterGroup(const Type& x, const Rank& l) /* This function allocates a CoxGroup of the given type and rank. More precisely, it allocates an object in the appropriate derived class of CoxGroup; in other words, it works as a virtual constructor for the CoxGroup class. */ { if (isTypeA(x)) { /* allocate a TypeACoxGroup */ if (l > MEDRANK_MAX) return new GeneralTypeABRCoxGroup(l); else if (l > SMALLRANK_MAX) return new GeneralTypeAMRCoxGroup(l); else if (l > maxSmallRank(x)) return new GeneralTypeASRCoxGroup(l); else /* group is small */ return new GeneralTypeASCoxGroup(l); } else if (isFiniteType(x)) { /* allocate a FiniteCoxGroup */ if (l > MEDRANK_MAX) return new GeneralFBRCoxGroup(x,l); else if (l > SMALLRANK_MAX) return new GeneralFMRCoxGroup(x,l); else if (l > maxSmallRank(x)) return new GeneralFSRCoxGroup(x,l); else /* group is small */ return new GeneralSCoxGroup(x,l); } else if (isAffineType(x)) { /* allocate an AffineCoxGroup */ if (l > MEDRANK_MAX) return new GeneralABRCoxGroup(x,l); else if (l > SMALLRANK_MAX) return new GeneralAMRCoxGroup(x,l); else /* l <= SMALLRANK_MAX */ return new GeneralASRCoxGroup(x,l); } else { /* allocate a GeneralCoxGroup */ if (l > MEDRANK_MAX) return new BigRankCoxGroup(x,l); else if (l > SMALLRANK_MAX) return new MedRankCoxGroup(x,l); else return new SmallRankCoxGroup(x,l); } } CoxEntry getCoxEntry(const Rank& i, const Rank& j) /* This function gets a Coxeter matrix entry from the user. It prompts until it gets a valid entry, or a carriage return, taking the latter to mean an instruction to abort the procedure. */ { static String buf(0); Ulong m = undef_coxentry; do { if (ERRNO) Error(ERRNO,i,j,m); printf("\nm[%d,%d] : ",i,j); getInput(stdin,buf); if (buf[0] == '\0') { /* abort */ ERRNO = BAD_COXENTRY; return undef_coxentry; } m = strtol(buf.ptr(),NULL,0); checkCoxEntry(i,j,m); } while (ERRNO); return static_cast(m) ; } }; namespace { void getCoxFileName(String& str) /* This function gets from the user the name of the file containing the coxeter matrix. It is called if the type is set to X. It checks if the given name corresponds to a file under coxeter_matrices. As usual, it prompts until it gets a valid name or a carriage return, taking the latter to mean an instruction to abort the procedure. */ { static String buf(0); using directories::COXMATRIX_DIR; reset(buf); append(buf,COXMATRIX_DIR); append(buf,"/"); Ulong c = buf.length(); do { if (ERRNO) { Error(ERRNO,buf.ptr()); reset(buf); append(buf,COXMATRIX_DIR); append(buf,"/"); } printf("\nFile name : %s/",COXMATRIX_DIR); getInput(stdin,buf,buf.length()); if (buf[c] == '\0') { /* abort */ ERRNO = ABORT; return; } checkFilename(buf.ptr()); } while (ERRNO); str.setLength(buf.length()-c+1); str[0] = 'X'; str.setData(buf.ptr()+c,1,buf.length()-c); str[str.length()] = '\0'; return; } }; namespace interactive { const CoxWord& getCoxWord(CoxGroup *W) /* This function gets a coxword from the user. If the input is not acceptable, it points at the first mistake and asks for better input. */ { static ParseInterface P; P.reset(); do { if (ERRNO) { P.str[P.offset] = '\0'; Error(ERRNO,P.str.ptr()); } getInput(stdin,P.str,P.offset); if (P.str[P.offset] == '?') { ERRNO = ABORT; return P.a[0]; } W->parse(P); if (P.offset != P.str.length()) ERRNO = PARSE_ERROR; } while (ERRNO); return P.a[0]; } Generator getGenerator(CoxGroup* W) /* This function gets a generator from the user. The string should start with "l" or "r" according to whether right or left action is desired. NOTE : it is assumed that the rank is restricted to accomodate the kl setup, i.e. in particular that 2*rank <= GENERATOR_MAX. */ { static String buf(0); const Interface& I = W->interface(); Generator s = undef_generator; Ulong r = 0; reset(buf); do { if (ERRNO) { buf[r] = '\0'; Error(ERRNO,buf.ptr()); } getInput(stdin,buf,r); if (buf[r] == '?') { ERRNO = ABORT; return undef_generator; } r = parse(I,s,buf); } while (ERRNO); return s; } Generator getGenerator(CoxGroup* W, const LFlags& f) /* Like getGenerator, but moreover checks if s is flagged by f. */ { static String buf(0); const Interface& I = W->interface(); Generator s = undef_generator; Ulong r = 0; reset(buf); do { if (ERRNO) { buf[r] = '\0'; Error(ERRNO,buf.ptr()); } getInput(stdin,buf,r); if (buf[r] == '?') { ERRNO = ABORT; return undef_generator; } r = parse(I,s,buf,f); } while (ERRNO); return s; } void getLength(List& L, const CoxGraph& G, const Interface& I) /* This function gets lengths of generators from the user, for computing polynomials with unequal parameters. We restrict ourselves to length functions with non-negative integer values; recall that values are constant on conjugacy classes of generators, and that these conjugacy classes are obtained by taking connected components of the Coxeter graph with all even- and infinite-labelled edges removed. It is assumed that L has already been allocated to the right size. */ { List cl(0); static String buf(0); getConjugacyClasses(cl,G); printf("There are %lu conjugacy classes of generators.",cl.size()); printf(" Enter lengths (? to abort):\n\n"); for (Ulong j = 0; j < cl.size(); ++j) { /* get length for class #j */ Ulong l = 0; Ulong trials = 0; do { if (trials >= 5) { ERRNO = ABORT; return; } ++trials; if (ERRNO) { Error(ERRNO,l); } print(stdout,cl[j],I); printf(" : "); getInput(stdin,buf); if (buf[0] == '?') { ERRNO = ABORT; return; } l = strtol(buf.ptr(),NULL,0); checkLength(l); } while (ERRNO); /* set corresponding lengths */ for (LFlags f = cl[j]; f; f &= f-1) { Generator s = firstBit(f); L[s] = l; L[s+G.rank()] = l; // left multiplication } } return; } Rank getRank(const Type& type) /* This function gets a rank from the user, corresponding to the given type. In case of invalid input, it prompts for better input, until it gets it, or until it gets a carriage return, (in which case it quits unsuccessfully). */ { static String buf(0); Rank l; int ignore_error; if (strchr("GI",type[0])) /* rank is 2 */ { printf("\nsetting rank to 2\n"); if (type[0] == 'G') printf("\n"); return 2; } ignore_error = 0; reset(buf); do { if (ERRNO) Error(ERRNO,&type,&l,&ignore_error); if (ignore_error) break; printf("\nrank : "); getInput(stdin,buf); if (buf[0] == '\0') { /* abort */ ERRNO = ERROR_WARNING; return 0; } l = (Rank)strtol(buf.ptr(),NULL,0); checkRank(l,type); } while (ERRNO); return l; } const Type& getType() /* This function gets a type from the user. In case of invalid input, it prompts for a better answer, until it gets it, or gets a carriage return (in which case it quits unsuccessfully). NOTE : the return value is safe until the next call to getType. */ { static Type buf(""); String& name = buf.name(); reset(name); do { if (ERRNO) Error(ERRNO); printf("\ntype : "); getInput(stdin,name); if (name[0] == '\0') { /* abort */ ERRNO = ABORT; return undef_type; } checkType(name); } while (ERRNO); /* give the user another chance */ return buf; } CoxEntry readCoxEntry(const Rank& i, const Rank& j, FILE *inputfile) /* Reads the entry i,j of a Coxeter matrix from the file inputfile. */ { Ulong m; fscanf(inputfile,"%lu",&m); checkCoxEntry(i,j,m); if (ERRNO) { Error(ERRNO,i,j,m); ERRNO = ABORT; return 1; } return m; } }; /***************************************************************************** Chapter III --- Configuration. This section contains functions which allow the user to configure some of the interface aspects. The functions are the following : - changeOrdering(W,order) : changes the ordering of generators; ******************************************************************************/ void interactive::changeOrdering(CoxGroup *W, Permutation& order) /* This function allows the user to specify a new ordering of the generators. He should input the standard generators in the ordering that he wants them (this is perhaps easier than to work from the current ordering, which would have been another possibility.) */ { static CoxWord g(0); printRepresentation(stdout,W); printf("Current ordering of the generators:\n\n\t"); printOrdering(stdout,W); printf("\n\n"); printf ("To change the numbering of the generators, enter the Coxeter element\n"); printf ("for which the generators are written in their new ordering (use the\n"); printf ("current symbols, prefix, postfix and separator)\n\n"); printf("new ordering : "); do { if (ERRNO) Error(ERRNO); g = getCoxWord(W); if (g.length() == 0) ERRNO = ABORT; if (ERRNO) /* abort */ return; checkCoxElement(W,g); } while (ERRNO); /* transfer ordering to the permutation */ for (Generator s = 0; s < W->rank(); s++) order[s] = g[s]-1; return; } /***************************************************************************** Chapter IV --- Quality checks This sections regroup the various functions that verify if the input is legal in the current situation. They are : - checkCoxElement(W,g) : checks if g is a reduced expression of a Coxeter element in W; - checkCoxEntry(i,j,m) : checks if m is a valid entry in position (i,j) in a Coxeter matrix; - checkFilename(s) : checks if s is the name of a file in the current directory; - checkLength(l) : checks if l is a legal length; - checkRank(l,type) : checks if $l$ is a legal rank for type; - checkType(str) : checks if str holds a legal typename; ******************************************************************************/ namespace { void checkCoxElement(CoxGroup *W, CoxWord g) /* Checks if g is a reduced expression of a Coxeter element in W --- in other words, if it is a permutation of the generators. */ { static bits::BitMap CCE_map(W->rank()); CCE_map.reset(); for (Length j = 0; g[j]; ++j) { Generator s = g[j] - 1; if (CCE_map.getBit(s)) { /* error */ ERRNO = NOT_COXELT; return; } CCE_map.setBit(s); } return; } void checkCoxEntry(Rank i, Rank j, Ulong m) /* Checks if m is a valid Coxeter entry for indices i, j. The value 0 is accepted, and represents infinity. */ { if (i == j) { if (m != 1) ERRNO = WRONG_COXETER_ENTRY; return; } if ((m == 1) || (m > COXENTRY_MAX)) ERRNO = WRONG_COXETER_ENTRY; return; } void checkFilename(char *s) /* Checks if s is the name of a file in the current directory, by attempting to open it. Does not check the contents of the file. */ { FILE *f; f = fopen(s,"r"); if (f == NULL) { /* error */ ERRNO = FILE_NOT_FOUND; return; } fclose(f); return; } void checkLength(const long& l) /* Checks if l is an acceptable length. Acceptable values are nonnegative integers between 0 and LENGTH_MAX. Sets the error BAD_LENGTH in case of failure. */ { if ((l < 0) || (l > LENGTH_MAX)) { ERRNO = BAD_LENGTH; } return; } void checkRank(const Rank& l, const Type& type) /* It is assumed that W->type() has been succesfully filled in. This function checks if l is a legal value for the rank. NOTE : this should be plusplussified somewhat more ! for instance, define a more sophisticated Type class with its own rank-checking capacity (a virtual function maybe.) */ { switch(type[0]) { case 'A': if ((l < 1) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'B': if ((l < 2) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'D': if ((l < 2) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'E': if ((l < 3) || (l > 8)) ERRNO = WRONG_RANK; break; case 'F': if ((l < 3) || (l > 4)) ERRNO = WRONG_RANK; break; case 'G': if (l != 2) ERRNO = WRONG_RANK; break; case 'H': if ((l < 2) || (l > 4)) ERRNO = WRONG_RANK; break; case 'I': if (l != 2) ERRNO = WRONG_RANK; break; case 'a': if ((l < 2) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'b': if ((l < 3) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'c': if ((l < 3) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'd': if ((l < 5) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'e': if ((l < 7) || (l > 9)) ERRNO = WRONG_RANK; break; case 'f': if (l != 5) ERRNO = WRONG_RANK; break; case 'g': if (l != 3) ERRNO = WRONG_RANK; break; case 'X': if ((l < 1) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; case 'Y': if ((l < 1) || (l > RANK_MAX)) ERRNO = WRONG_RANK; break; } return; } void checkType(String& str) /* Checks if the string s is a valid type for a Coxeter group. Currently the valid types are one-letter strings (this might change, for instance if non-irreducible groups are permitted). The valid types are : - A-I, corresponding to the finite Coxeter groups; - a-g, corresponding to the affine Coxeter groups; - X/x, for input from a file; - Y/y, for interactive input. In the case of type X/x, the name of the file is appended to s, so that the type will then be an actual string. It is assumed that the string holds at least a character. */ { if (str.length() > 1) { /* string too long */ ERRNO = WRONG_TYPE; return; } if ((str[0] >= 'A') && (str[0] <= 'I')) { if (str[0] == 'C') { printf("\nwarning: type was changed to B\n"); str[0] = 'B'; } return; } if ((str[0] >= 'a') && (str[0] <= 'g')) return; if ((str[0] == 'X') || (str[0] == 'x')) { getCoxFileName(str); return; } if ((str[0] == 'Y') || (str[0] == 'y')) { str[0] = 'Y'; return; } ERRNO = WRONG_TYPE; return; } }; /***************************************************************************** Chapter V -- PrettyPrinting. This section regroups various functions for prettyprinting information about the Coxeter group. The following functions are provided : - printInterface(file,W,GI) : prints GI using W's input generators; - printMatrix(file,W) : prints the Coxeter matrix on the outputfile; - printOrdering(file,W) : prints the ordering of the generators; - printRepresentation(file,W) : prints the numbering of the generators; *****************************************************************************/ namespace interactive { void printInterface(FILE* file, const GroupEltInterface& GI, const Permutation& a) { fprintf(file,"prefix: "); print(file,GI.prefix); fprintf(file,"\n"); fprintf(file,"separator: "); print(file,GI.separator); fprintf(file,"\n"); fprintf(file,"postfix: "); print(file,GI.postfix); fprintf(file,"\n"); for (Ulong j = 0; j < a.size(); ++j) { fprintf(file,"generator "); Generator s = a[j]; print(file,GI.symbol[s]); fprintf(file,"\n"); } return; } void printInterface(FILE* file, const GroupEltInterface& GI, const GroupEltInterface& WI, const Permutation& a) { fprintf(file,"prefix: "); print(file,GI.prefix); fprintf(file,"\n"); fprintf(file,"separator: "); print(file,GI.separator); fprintf(file,"\n"); fprintf(file,"postfix: "); print(file,GI.postfix); fprintf(file,"\n"); for (Ulong j = 0; j < a.size(); ++j) { fprintf(file,"generator "); Generator s = a[j]; print(file,WI.symbol[s]); fprintf(file,": "); print(file,GI.symbol[s]); fprintf(file,"\n"); } return; } void printMatrix(FILE* file, const CoxGroup* W) /* Prints the Coxeter matrix on file. */ { Permutation a(W->interface().order()); a.inverse(); for (Ulong i = 0; i < W->rank(); ++i) { for (Ulong j = 0; j < W->rank(); j++) { fprintf(file,"%4d",W->M(a[i],a[j])); } fprintf(file,"\n"); } return; } void printOrdering(FILE* file, const CoxGroup* W) /* Prints the current ordering of the generators. */ { Permutation a(W->interface().order()); a.inverse(); for (Ulong j = 0; j < a.size(); ++j) { Generator s = a[j]; print(file,W->interface().inSymbol(s)); if (j+1 < a.size()) /* there is more to come */ fprintf(file," < "); } return; } void printRepresentation(FILE* file, const CoxGroup* W) /* Prints the numbering of the generators on the file, for the predefined types. */ { switch (W->type()[0]) { case 'A': fprintf(file,"The labelling of the generators is as follows :\n\n"); printADiagram(file,W); fprintf(file,"\n"); return; case 'B': fprintf(file,"The labelling of the generators is as follows :\n\n"); printBDiagram(file,W); fprintf(file,"\n"); return; case 'D': fprintf(file,"The labelling of the generators is as follows :\n\n"); printDDiagram(file,W); fprintf(file,"\n"); return; case 'E': fprintf(file,"The labelling of the generators is as follows :\n\n"); printEDiagram(file,W); fprintf(file,"\n"); return; case 'F': fprintf(file,"The labelling of the generators is as follows :\n\n"); printFDiagram(file,W); fprintf(file,"\n"); return; case 'G': fprintf(file,"The labelling of the generators is as follows :\n\n"); printGDiagram(file,W); fprintf(file,"\n"); return; case 'H': fprintf(file,"The labelling of the generators is as follows :\n\n"); printHDiagram(file,W); fprintf(file,"\n"); return; case 'I': fprintf(file,"The labelling of the generators is as follows :\n\n"); printIDiagram(file,W); fprintf(file,"\n"); return; default: fprintf(file,"The current Coxeter matrix is as follows :\n\n"); printMatrix(file,W); fprintf(file,"\n"); return; }; } }; namespace { void printADiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); if (W->rank() <= 8) { /* rank is at least 4 */ print(file,I.inSymbol(0)); for (Generator s = 1; s < W->rank(); ++s) { fprintf(file," - "); print(file,I.inSymbol(s)); } } else { print(file,I.inSymbol(0)); fprintf(file," - "); print(file,I.inSymbol(1)); fprintf(file," - ... - "); print(file,I.inSymbol(W->rank()-1)); } fprintf(file,"\n"); return; } void printBDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); if (W->rank() <= 8) { /* rank is at least 4 */ print(file,I.inSymbol(0)); fprintf(file," = "); print(file,I.inSymbol(1)); for (Generator s = 2; s < W->rank(); ++s) { fprintf(file," - "); print(file,I.inSymbol(s)); } } else { print(file,I.inSymbol(0)); fprintf(file," = "); print(file,I.inSymbol(1)); fprintf(file," - ... - "); print(file,I.inSymbol(W->rank()-1)); } fprintf(file,"\n"); return; } void printDDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); if (W->rank() <= 8) { print(file,I.inSymbol(0)); fprintf(file," - "); print(file,I.inSymbol(2)); for (Generator s = 3; s < W->rank(); ++s) { fprintf(file," - "); print(file,I.inSymbol(s)); } int c = I.inSymbol(0).length() + 3; c += I.inSymbol(2).length()/2; printf("\n\t%*s|",c,""); c -= I.inSymbol(1).length()/2; if (c < 0) c = 0; printf("\n\t%*s",c,""); print(file,I.inSymbol(1)); } else { print(file,I.inSymbol(0)); fprintf(file," - "); print(file,I.inSymbol(2)); fprintf(file," - ... - "); print(file,I.inSymbol(W->rank()-1)); int c = I.inSymbol(0).length() + 3; c += I.inSymbol(2).length()/2; printf("\n\t%*s|",c,""); c -= I.inSymbol(1).length()/2; if (c < 0) c = 0; printf("\n\t%*s",c,""); print(file,I.inSymbol(1)); } fprintf(file,"\n"); return; } void printEDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); print(file,I.inSymbol(0)); fprintf(file," - "); print(file,I.inSymbol(2)); fprintf(file," - "); print(file,I.inSymbol(3)); for (Generator s = 4; s < W->rank(); ++s) { fprintf(file," - "); print(file,I.inSymbol(s)); } int c = I.inSymbol(0).length() + I.inSymbol(2).length() + 6; c += I.inSymbol(3).length()/2; printf("\n\t%*s|",c,""); c -= I.inSymbol(1).length()/2; if (c < 0) c = 0; printf("\n\t%*s",c,""); print(file,I.inSymbol(1)); fprintf(file,"\n"); return; } void printFDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); print(file,I.inSymbol(0)); fprintf(file," - "); print(file,I.inSymbol(1)); fprintf(file," = "); print(file,I.inSymbol(2)); fprintf(file," - "); print(file,I.inSymbol(3)); return; } void printGDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); int c = I.inSymbol(0).length() + 1; fprintf(file,"%*s6\n",c,""); fprintf(file,"\t"); print(file,I.inSymbol(0)); fprintf(file," - "); print(file,I.inSymbol(1)); return; } void printHDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); fprintf(file,"\t"); int c = I.inSymbol(0).length() + 1; fprintf(file,"%*s5\n",c,""); fprintf(file,"\t"); print(file,I.inSymbol(0)); for (Generator s = 1; s < W->rank(); ++s) { fprintf(file," - "); print(file,I.inSymbol(s)); } return; } void printIDiagram(FILE* file, const CoxGroup* W) { const Interface& I = W->interface(); /* print the tag */ CoxEntry m = W->M(0,1); fprintf(file,"\t"); int c = I.inSymbol(0).length() + 1; fprintf(file,"%*s%d\n",c,"",m); /* print the symbols */ int d = digits(m,10); fprintf(file,"\t"); print(file,I.inSymbol(0)); fprintf(file," "); for (int j = 0; j < d; ++j) fprintf(file,"-"); fprintf(file," "); print(file,I.inSymbol(1)); return; } }; /***************************************************************************** Chapter VI --- Miscellaneous. This chapter regroups various functions that did not seem to fall into any of the other categories : - EndOfLine(f) : an auxiliary in getting input from a file; - parse(I,s,line) : parses s from line; - yesNo() : collects yes or no for an answer; ******************************************************************************/ int interactive::endOfLine(FILE *f) /* This function reads characters from the file f until the first non-white character has been found (which is pushed back), or newline is found. It returns 0 in the first case, 1 in the second. In any case, the character is pushed back (it also returns 1 if EOF is encountered.) */ { int c; while((c = getc(f)) != EOF) { if (!isspace(c)) { ungetc(c,f); return 0; } if (c == '\n') { ungetc(c,f); return 1; } } /* if we get here we have reached EOF */ return 1; } namespace { Ulong parse(const Interface& I, Generator &s, const String& line) /* This function parses a generator from the line. After skipping over white space, the string should contain one of the letters "l" or "r", followed by the input symbol of a generator. The only other possibility is the empty (= white) string. */ { Token tok; Ulong q = io::skipSpaces(line,0); const char* str = line.ptr()+q; Ulong strsize = line.length()-q; if (strsize == 0) { /* default generator */ s = undef_generator; return q; } switch (str[0]) { /* should be 'l' or 'r' */ case 'l': s = I.rank(); break; case 'r': s = 0; break; default: ERRNO = PARSE_ERROR; return q; } str++; strsize--; q++; q += io::skipSpaces(line,q); str = line.ptr()+q; Ulong p = I.symbolTree().find(str,0,tok); if (tokenType(tok) != interface::generator_type) { /* error */ ERRNO = PARSE_ERROR; return q; } s += tok-1; q += p; return q; } Ulong parse(const Interface& I, Generator &s, const String& line, const LFlags& f) /* This function parses a generator from the line, checking if the generator is flagged by f. After skipping over white space, the string should contain one of the letters "l" or "r", followed by the input symbol of a generator. The only other possibility is the empty (= white) string. */ { Token tok; Ulong q = io::skipSpaces(line,0); const char* str = line.ptr()+q; Ulong strsize = line.length()-q; if (strsize == 0) { /* default generator */ s = undef_generator; return q; } switch (str[0]) { /* should be 'l' or 'r' */ case 'l': s = I.rank(); break; case 'r': s = 0; break; default: ERRNO = PARSE_ERROR; return q; } str++; strsize--; q++; q += io::skipSpaces(line,q); str = line.ptr()+q; strsize = line.length()-q; Ulong p = I.symbolTree().find(str,0,tok); if (tokenType(tok) != interface::generator_type) { /* error */ ERRNO = PARSE_ERROR; return q; } if (!(f & lmask[s+tok-1])) { /* error */ ERRNO = NOT_DESCENT; return q; } s += tok-1; q += p; return q; } }; namespace interactive { bool yesNo() /* Gets a yes or a no from the user. */ { String buf(0); do { if (ERRNO) { fprintf(stderr,"please answer yes or no\n"); ERRNO = 0; } getInput(stdin,buf); char c = buf[0]; if (c == 'y') return true; if (c == 'n') return false; ERRNO = NOT_YN; } while (ERRNO); return true; // should be unreachable } }; positivity_final/interactive.h0000600000175000017500000000417310011171251020312 0ustar duclouxducloux00000000000000/* This is interactive.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef INTERACTIVE_H /* guard against multiple inclusions */ #define INTERACTIVE_H #include "globals.h" namespace interactive { using namespace globals; }; /******** type declarations *************************************************/ namespace interactive { class OutputFile; }; #include "bits.h" #include "coxtypes.h" #include "graph.h" #include "interface.h" #include "transducer.h" #include "type.h" namespace interactive { using namespace bits; using namespace coxgroup; using namespace coxtypes; using namespace graph; using namespace interface; using namespace transducer; using namespace type; }; /******** function declarations **********************************************/ namespace interactive { CoxGroup* allocCoxGroup(); CoxGroup* allocCoxGroup(const Type& x); void changeOrdering(CoxGroup *W, Permutation& order); CoxGroup* coxeterGroup(const Type& x, const Rank& l); int endOfLine(FILE *f); const Type& getType(); CoxEntry getCoxEntry(const Rank& i, const Rank& j); CoxArr& getCoxArr(Transducer& T) /* not implemented */; CoxNbr& getCoxNbr(Transducer& T) /* not implemented */; const CoxWord& getCoxWord(CoxGroup *W); Generator getGenerator(CoxGroup *W); Generator getGenerator(CoxGroup *W, const LFlags& f); void getLength(List& L, const CoxGraph& G, const Interface& I); Rank getRank(const Type& type); void printInterface(FILE* file, const GroupEltInterface& GI, const Permutation& a); void printInterface(FILE* file, const GroupEltInterface& GI, const GroupEltInterface& WI, const Permutation& a); void printMatrix(FILE *file, const CoxGroup* W); void printOrdering(FILE* file, const CoxGroup* W); void printRepresentation(FILE *file, const CoxGroup* W); CoxEntry readCoxEntry(const Rank& i, const Rank& j, FILE *inputfile); bool yesNo(); }; /* type definitions */ namespace interactive { class OutputFile { private: FILE* d_file; public: OutputFile(); ~OutputFile(); FILE* f() {return d_file;} }; }; #endif positivity_final/interface.cpp0000600000175000017500000013432310011171251020271 0ustar duclouxducloux00000000000000/* This is interface.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "interface.h" #include #include "bits.h" #include "error.h" namespace interface { using namespace error; }; /******** local declarations *************************************************/ namespace { using namespace interface; const char *alphabet = "abcdefghijklmnopqrstuvwxyz"; const char *affine = "abcdefg"; const Token not_token = RANK_MAX+1; const Token prefix_token = RANK_MAX+2; const Token postfix_token = RANK_MAX+3; const Token separator_token = RANK_MAX+4; const Token begingroup_token = RANK_MAX+5; const Token endgroup_token = RANK_MAX+6; const Token longest_token = RANK_MAX+7; const Token inverse_token = RANK_MAX+8; const Token power_token = RANK_MAX+9; const Token contextnbr_token = RANK_MAX+10; const Token densearray_token = RANK_MAX+11; const unsigned prefix_bit = 0; const unsigned postfix_bit = 1; const unsigned separator_bit = 2; }; namespace { using namespace interface; void makeSymbols(List& list, const String* const symbol, Ulong n); CoxNbr toCoxNbr(char c); Automaton *tokenAutomaton(LFlags f); Automaton *tokenAut0(); Automaton *tokenAut1(); Automaton *tokenAut2(); Automaton *tokenAut3(); Automaton *tokenAut4(); Automaton *tokenAut5(); Automaton *tokenAut6(); Automaton *tokenAut7(); }; /**************************************************************************** This module defines the interface class, which takes care of input/output of elements in the group. We are careful to distinguish between external and internal representation of our elements. The internal representation is always the same : the default one is as reduced coxwords (arrays for finite groups, numbers for small groups.) We do not in fact insist that our reduced word be normalized; so equality will be a relatively expensive test. Externally, the user has two levels of flexibility. First of all, to each integer in {1,...,n}, where n is the rank, there is associated a symbol (in fact two symbols, an input symbol --- some non-empty string --- and an output symbol, an arbitrary string). The default is input = output = the decimal representation of the number. Furthermore, there are three arbitrary strings : prefix, postfix and separator, also with an input and an output version. Default is prefix and postfix empty, separator empty if the rank is <= 9, "." otherwise. The second level is the possibility to define an arbitrary ordering on the generators. Each group has a "standard" ordering, built-in in the case of finite or affine groups, and implicitly defined by the datum of the Coxeter matrix for general groups. However, the user may change this ordering if he wishes. This setup is easy to implement, and gives more than enough flexibility to read from and write to programs like Gap, Magma or Maple, or even TeX, and to perform some other nifty output tricks (outputting a k-l basis element in Gap format, say, is a breeze.) Also the program can read from one program and write to another, functioning as a pipe. ****************************************************************************/ /**************************************************************************** Chapter I -- The Interface class. This class regroups the facilities through which a CoxGroup communicates with the outside world. The following functions are defined : constructors : - Interface(x,l) : constructs the standard interface in type x and rank l; - ~Interface() : (not implemented yet); manipulators : - readSymbols() : updates the symbol tree for the group; - setAutomaton() : resets the value of the automaton; - setIn(i) : resets the input interface to i; - setInPostfix(a) : changes the input postfix; (inlined) - setInPrefix(a) : changes the input prefix; (inlined) - setInSeparator(a) : changes the input separator; (inlined) - setInSymbol(s,a) : changes the input symbol; (inlined) - setOrder(gen_order) : changes the perceived ordering of the generators; - setOut(i) : resets the output interface to i; - setOutPrefix(a) : changes the output prefix; (inlined) - setOutPostfix(a) : changes the output postfix; (inlined) - setOutSeparator(a) : changes the output separator; (inlined) - setOutSymbol(s,a) : changes the output symbol; (inlined) accessors : - in(s) : returns the internal number of the generator placed in s-th position by the user (inlined); - out(s) : returns the user-number of the s-th internal generator (inlined); - outOrder() : returns the array [out(s), 0 <= s < rank] (inlined); - rank() : returns the rank (inlined); input/output functions : - parse(T,g,line,r,x) : parses a CoxWord from line; - print(file,g) : prints the coxword g; - print(file,f) : prints a list of the generators flagged by f; ****************************************************************************/ namespace interface { Interface::Interface(const Type& x, const Rank& l) :d_order(l), d_beginGroup("("), d_endGroup(")"), d_longest("*"), d_inverse("!"), d_power("^"), d_contextNbr("%"), d_denseArray("#"), d_parseEscape("?"), d_reserved(0), d_rank(l) /* Constructs the default interface (see the introduction.) */ { d_order = identityOrder(l); d_in = new GroupEltInterface(l); d_out = new GroupEltInterface(l); d_descent = new DescentSetInterface; insert(d_reserved,d_beginGroup); insert(d_reserved,d_endGroup); insert(d_reserved,d_longest); insert(d_reserved,d_inverse); insert(d_reserved,d_power); insert(d_reserved,d_contextNbr); insert(d_reserved,d_denseArray); insert(d_reserved,d_parseEscape); readSymbols(); setAutomaton(); } Interface::~Interface() /* We just have to delete d_in and d_out. */ { delete d_out; delete d_in; } /******** manipulators ******************************************************/ void Interface::readSymbols() /* Reads the input symbols into the symbol tree. This should be used each time the input symbols are reset. The safest way to avoid running into trouble is simply building the tree again. It is important that no meaningless symbols remain on the tree. (an alternative would have been to mark them as meaningless, through a special token.) */ { d_symbolTree.~TokenTree(); new(&d_symbolTree) TokenTree; if (inPrefix().length()) d_symbolTree.insert(inPrefix(),prefix_token); if (inSeparator().length()) d_symbolTree.insert(inSeparator(),separator_token); if (inPostfix().length()) d_symbolTree.insert(inPostfix(),postfix_token); for (Generator s = 0; s < rank(); ++s) { d_symbolTree.insert(inSymbol(s),s+1); } d_symbolTree.insert(d_beginGroup,begingroup_token); d_symbolTree.insert(d_endGroup,endgroup_token); d_symbolTree.insert(d_longest,longest_token); d_symbolTree.insert(d_inverse,inverse_token); d_symbolTree.insert(d_power,power_token); d_symbolTree.insert(d_contextNbr,contextnbr_token); d_symbolTree.insert(d_denseArray,densearray_token); return; } void Interface::setAutomaton() { LFlags f = 0; using constants::lmask; if (d_in->prefix.length()) f |= lmask[prefix_bit]; if (d_in->postfix.length()) f |= lmask[postfix_bit]; if (d_in->separator.length()) f |= lmask[separator_bit]; d_tokenAut = tokenAutomaton(f); return; } void Interface::setDescent(Default) /* Resets the DescentSetInterface to the default parameters. */ { new(d_descent) DescentSetInterface(); return; } void Interface::setDescent(GAP) /* Resets the DescentSetInterface to GAP parameters. */ { new(d_descent) DescentSetInterface(GAP()); return; } void Interface::setIn(const GroupEltInterface& i) /* Resets d_in to i. */ { delete d_in; d_in = new GroupEltInterface(i); readSymbols(); setAutomaton(); return; } void Interface::setOrder(const Permutation& order) /* Resets the numbering of the generators. The given ordering is the ordering of our generators as the user wants them. What we record in d_order is rather the inverse permutation : d_order[i] is the number in the user's order of our generator i. */ { for (Generator s = 0; s < rank(); ++s) { d_order[order[s]] = s; } return; } void Interface::setOut(const GroupEltInterface& i) /* Resets d_out to i */ { delete d_out; d_out = new GroupEltInterface(i); return; } /******** input-output *******************************************************/ bool Interface::parseCoxWord(ParseInterface& P, const MinTable& T) const /* This function parses a CoxWord from the line, starting at position r, and increments the CoxWord g with it. The syntax for a group element is as follows : prefix [generator [separator generator]*] postfix Here prefix, postfix, and separator, and the symbols representing the generators, are a priori arbitrary strings without whitespace, subject only to the condition that they be distinct. Tokens are taken from the input string, after skipping over leading whitespaces (so tokens could actually contain embedded whitespace, but no leading whitespace.) The symbols have been put on a tree, which makes it easy to read them and to take care of the (very real!) possibility of embedded symbols. The tokens are then processed by a little finite state automaton which checks syntactical correctness; in case of failure, the error PARSE_ERROR is set. The return value is the number of characters successfully read, enabling the caller to position the cursor just after the whitespace following the last token successfully read. An additional complication comes from the fact that we wish to allow the strings prefix, postfix and separator to be empty --- so in fact there are eight variants of the syntactical automaton (this seemed easier to do than to try to cover all cases at once.) The appropriate automaton is loaded when the interface is created, or modified. */ { Token tok = 0; while (Ulong p = getToken(P,tok)) { Letter tok_type = tokenType(tok); if (tok_type > separator_type) /* end of coxword */ break; State y = d_tokenAut->act(P.x,tok_type); if (d_tokenAut->isFailure(y)) /* end of coxword */ break; P.x = y; if (tok_type == generator_type) { Generator s = tok-1; T.prod(P.c,s); } P.offset += p; } if (d_tokenAut->isAccept(P.x)) /* correct input */ P.x = 0; else /* incomplete input */ ERRNO = PARSE_ERROR; return true; } bool Interface::readCoxElt(ParseInterface& P) const /* This function attempts to read a Coxeter element from P. It does not have to worry about word reduction because all the generators read have to be distinct. NOTE : it is assumed that the rank is at most MEDRANK_MAX. */ { Token tok = 0; LFlags f = 0; // in case this is a second attempt after an incomplete read, make // f hold the part already read for (Ulong j = 0; j < P.c.length(); ++j) f |= lmask[P.c[j]-1]; // read new part while (Ulong p = getToken(P,tok)) { Letter tok_type = tokenType(tok); if (tok_type > separator_type) /* end of coxword */ break; State y = d_tokenAut->act(P.x,tok_type); if (d_tokenAut->isFailure(y)) /* end of coxword */ break; P.x = y; if (tok_type == generator_type) { if (f & lmask[tok-1]) { // generator already appeared ERRNO = NOT_COXELT; return true; } f |= lmask[tok-1]; P.c.append(tok); } P.offset += p; } if (d_tokenAut->isAccept(P.x)) { /* input is subword of coxelt */ if ((f != 0) && (f != leqmask[rank()-1])) ERRNO = NOT_COXELT; else P.x = 0; } else { /* incomplete input */ ERRNO = PARSE_ERROR; } return true; } }; /**************************************************************************** Chapter II --- The DescentSetInterface class. This is the part of the interface used to write out descent sets. The meaning of the fields is as follows : - prefix : opening string; - postfix : closing string; - separator : separation between two entries; - twosidedPrefix : opening string for two-sided descent sets; - twosidedPostfix : closing string for two-sided descent sets; - twosidedSeparator : used to separate the left from the right part in the printout of two-sided descent sets. The symbols used for the generators are the ones from the current output GroupEltInterface. The following functions are defined : - constructors and destructors : - DescentSetInterface() : the default constructor; - DescentSetInterface(GAP) : constructor for GAP output; - ~DescentSetInterface() : destructor; - modifiers : - setPrefix(str) : sets the prefix to str; - setPostfix(str) : sets the postfix to str; - setSeparator(str) : sets the separator to str; - setTwosidedSeparator(str) : sets the 2-sided separator to str; *****************************************************************************/ namespace interface { DescentSetInterface::DescentSetInterface() :prefix("{"),postfix("}"),separator(","),twosidedPrefix("{"), twosidedPostfix("}"),twosidedSeparator(";") /* Sets the default values for the interface. */ {} DescentSetInterface::DescentSetInterface(GAP) :prefix("["),postfix("]"),separator(","),twosidedPrefix("[["), twosidedPostfix("]]"),twosidedSeparator("],[") {} DescentSetInterface::~DescentSetInterface() {} void DescentSetInterface::setPrefix(const String& str) { prefix = str; return; } void DescentSetInterface::setPostfix(const String& str) { postfix = str; return; } void DescentSetInterface::setSeparator(const String& str) { separator = str; return; } void DescentSetInterface::setTwosidedPrefix(const String& str) { twosidedPrefix = str; return; } void DescentSetInterface::setTwosidedPostfix(const String& str) { twosidedPostfix = str; return; } void DescentSetInterface::setTwosidedSeparator(const String& str) { twosidedSeparator = str; return; } }; /**************************************************************************** Chapter III --- The GroupEltInterface class. This is the part of the interface used to read and write group elements in word form. The following functions are defined : - constructors and destructors : - GroupEltInterface(); - GroupEltInterface(l); - GroupEltInterface(l,Gap); - ~GroupEltInterface(); - accessors : - print(file); - manipulators : - setPostfix(a) : sets the postfix to a; - setPrefix(a) : sets the prefix to a; - setSeparator(a) : sets the separator to a; - setSymbol(s,a) : sets symbol # s to a; ****************************************************************************/ namespace interface { GroupEltInterface::GroupEltInterface() :symbol(0),prefix(String::undefined()),postfix(String::undefined()), separator(String::undefined()) /* We use the default constructor to construct an interface where the symbol table is empty, and the prefix,postfix and separator strings are all undefined. It is not intended to be used other than in very special cases. NOTE : This is pretty dangerous, and should be much more hidden! */ {} GroupEltInterface::GroupEltInterface(const Rank& l) :symbol(l),prefix(0),postfix(0),separator(0) /* Constructs the default interface in rank l. */ { symbol.setSize(l); makeSymbols(symbol,decimalSymbols(l),l); if (l > 9) { /* need separators */ new(&separator) String("."); } } GroupEltInterface::GroupEltInterface(const Rank& l, Alphabetic) :symbol(l),prefix(""),postfix(""),separator("") /* Constructs the GAP interface in rank l. This represents Coxeter words as lists, with decimal symbols : for instance, the element 12321 in rank 3 would be represented as [1,2,3,2,1]. */ { symbol.setSize(l); makeSymbols(symbol,alphabeticSymbols(l),l); if (l > 26) separator = "."; } GroupEltInterface::GroupEltInterface(const Rank& l, Decimal) :symbol(l),prefix(""),postfix(""),separator("") /* Constructs the GAP interface in rank l. This represents Coxeter words as lists, with decimal symbols : for instance, the element 12321 in rank 3 would be represented as [1,2,3,2,1]. */ { symbol.setSize(l); makeSymbols(symbol,decimalSymbols(l),l); if (l > 9) separator = "."; } GroupEltInterface::GroupEltInterface(const Rank& l, GAP) :symbol(l),prefix("["),postfix("]"),separator(",") /* Constructs the GAP interface in rank l. This represents Coxeter words as lists, with decimal symbols : for instance, the element 12321 in rank 3 would be represented as [1,2,3,2,1]. */ { symbol.setSize(l); makeSymbols(symbol,decimalSymbols(l),l); } GroupEltInterface::GroupEltInterface(const Rank& l, Hexadecimal) :symbol(l),prefix(""),postfix(""),separator("") /* Constructs the hexadecimal interface in rank l. This represents Coxeter words as strings of hex digits if the rank is <= 15, dot-separated hex numbers otherwise. The symbol 0 is not used. */ { symbol.setSize(l); makeSymbols(symbol,hexSymbols(l),l); if (l > 15) separator = "."; } GroupEltInterface::GroupEltInterface(const Rank& l, HexadecimalFromZero) :symbol(l),prefix(""),postfix(""),separator("") /* Constructs the hexadecimal interface in rank l. This represents Coxeter words as strings of hex digits if the rank is <= 16, dot-separated hex numbers otherwise. The symbol 0 is used for the first generator. */ { symbol.setSize(l); makeSymbols(symbol,hexSymbolsFromZero(l),l); if (l > 16) separator = "."; } GroupEltInterface::~GroupEltInterface() /* Automatic destruction is enough. */ {} /******** accessors *********************************************************/ void GroupEltInterface::print(FILE* file) const { fprintf(file,"prefix: "); io::print(file,prefix); fprintf(file,"\n"); fprintf(file,"separator: "); io::print(file,separator); fprintf(file,"\n"); fprintf(file,"postfix: "); io::print(file,postfix); fprintf(file,"\n"); for (Generator s = 0; s < symbol.size(); ++s) { fprintf(file,"symbol #%d: ",s+1); io::print(file,symbol[s]); fprintf(file,"\n"); } return; } /******** manipulators ******************************************************/ void GroupEltInterface::setPostfix(const String& a) { postfix = a; return; } void GroupEltInterface::setPrefix(const String& a) { prefix = a; return; } void GroupEltInterface::setSeparator(const String& a) { separator = a; return; } void GroupEltInterface::setSymbol(const Generator& s, const String& a) /* Sets the symbol for generator s to a. Remember that the relation between symbols and numbers is not affected by the ordering of the generators; if the user changes the ordering, so that a generator previously numbered i is now numbered j, that generator will be represented by symbol j instead of symbol i; this is the expected behaviour, I think. */ { symbol[s] = a; return; } }; /**************************************************************************** Chapter IV -- The ReservedSymbol class. This is just a little structure to hold the symbols reserved for some basic operations. These cannot be used in the input-interface for group elements. Their redefinition should be possible, but is not implemented currently. NOTE : I'm having a little trouble using this --- not used currently. ****************************************************************************/ namespace interface { ReservedSymbols::ReservedSymbols() :beginGroup(0),endGroup(0),longest(0),inverse(0),power(0),contextnbr(0), densearray(0) {} ReservedSymbols::ReservedSymbols(Default) :beginGroup("("),endGroup(")"),longest("*"),inverse("!"),power("^"), contextnbr("%"),densearray("#") {} ReservedSymbols::~ReservedSymbols() {} }; /**************************************************************************** Chapter V -- Standard interfaces. This section defines some functions which facilitate the definiton of standard interfaces. The following functions are defined : - gapInput(I) : sets the input to GAP input (not implemented yet); - gapOutput(I) : sets the output to GAP output (not implemented yet); ( ... maple ? magma ? mathematica ?) - decimalSymbols() : returns a pointer to the list of decimal integers; - hexSymbols() : returns a pointer to the list of hexadecimal integers; - hexSymbolsFromZero() : returns a pointer to the list of hexadecimal integers, starting from zero; - twohexSymbols() : returns a pointer to the list of two-digit hex symbols; - alphabeticSymbols() : returns a pointer to the list of alphabetic symbols; ****************************************************************************/ namespace interface { const String* alphabeticSymbols(Ulong n) /* Produces an alphabetic representation of the numbers in {1,...,n}. In fact, the numbers from 0 are represented by strings of the form "", "a", ... , "z", "aa", ... , "az", "ba", ... through the following algorithm : for n > 0 the representation of n is the concatenation of rep((n-1)/b) with the letter (n-1)%b, where b is the base, i.e., the number of letters in the alphabet. In our case the role of n-1 is actually played by n. */ { static List list(0); static bool first = true; if (first) { first = false; list.setSize(1); new(list.ptr()) String(""); } if (n+1 > list.size()) { /* enlarge the list */ Ulong prev = list.size()-1; list.setSize(n+1); for (Ulong j = prev; j < n; ++j) { /* write symbol */ list[j+1].assign(list[j/26]); append(list[j+1],alphabet[j%26]); } } return list.ptr()+1; } const String* decimalSymbols(Ulong n) /* Returns a pointer to a list of strings, the first n of which contain the decimal string representations of the first n natural numbers. */ { static List list(0); if (n > list.size()) { /* enlarge the list */ Ulong prev_size = list.size(); list.setSize(n); for (Ulong j = prev_size; j < n; ++j) { /* write symbol */ list[j].setLength(io::digits(j+1,10)); sprintf(list[j].ptr(),"%lu",j+1); } } return list.ptr(); } const String* hexSymbolsFromZero(Ulong n) /* Returns a pointer to a list of strings, the first n of which contain the hexadecimal string representations of the first n integers, including zero. */ { static List list; if (n > list.size()) { /* enlarge the list */ Ulong prev_size = list.size(); list.setSize(n); for (Ulong j = prev_size; j < n; ++j) { /* write symbol */ list[j].setLength(io::digits(j,16)); sprintf(list[j].ptr(),"%lx",j); } } return list.ptr(); } const String* hexSymbols(Ulong n) /* Returns a pointer to a list of strings, the first n of which contain the hexadecimal string representations of the first n natural numbers. */ { static List list; if (n > list.size()) { /* enlarge the list */ Ulong prev_size = list.size(); list.setSize(n); for (Ulong j = prev_size; j < n; ++j) { /* write symbol */ list[j].setLength(io::digits(j+1,16)); sprintf(list[j].ptr(),"%lx",j+1); } } return list.ptr(); } const String* twohexSymbols(Ulong n) /* Returns a pointer to a list of strings, the first n of which contain the hexadecimal string representations of the first n natural numbers --- here we impose the condition that the width is at least two, with 0 as a padding character. For the range of possible ranks, this leads to constant-width symbols. */ { static List list; if (n > list.size()) { /* enlarge the list */ Ulong prev_size = list.size(); list.setSize(n); for (Ulong j = prev_size; j < n; ++j) { /* write symbol */ list[j].setLength(2*io::digits(j+1,256)); sprintf(list[j].ptr(),"%0*lx",2*io::digits(j+1,256),j+1); } } return list.ptr(); } const Permutation& identityOrder(Ulong n) { static Permutation list(0); static Ulong valid_range = 0; if (n > valid_range) { /* enlarge the list */ Ulong prev_size = valid_range; list.setSize(n); for (Ulong j = prev_size; j < n; ++j) list[j] = j; valid_range = n; } list.setSize(n); return list; } }; /**************************************************************************** Chapter VI -- The ParseInterface class. This class provides a convenient interface for the delicate operation of parsing. The point is that we wish to be able to parse interactively, and in particular give the user a chance to correct his mistakes; therefore the "state" of the parsing has to be recorded somewhere. The following functions are defined : - ParseInterface(); - ~ParseInterface(); - reset(); ****************************************************************************/ namespace interface { ParseInterface::ParseInterface() :str(0),nestlevel(0),a(1),c(0),x(0) { a.setSize(1); a[0].reset(); } ParseInterface::~ParseInterface() /* Automatic destruction is enough. */ {} void ParseInterface::reset() { str.setLength(0); nestlevel = 0; a.setSize(1); a[0].reset(); c.reset(); x = 0; offset = 0; } }; /**************************************************************************** Chapter VII -- The TokenTree class. This class is an auxiliary for the parsing of input, which we found a non-trivial business! Probably this could be done in terms of the Dictionary template. ****************************************************************************/ namespace interface { TokenCell::~TokenCell() { delete left; delete right; } TokenTree::TokenTree() { d_root = new TokenCell; } TokenTree::~TokenTree() { delete d_root; } Ulong TokenTree::find(const String& str, const Ulong& n, Token& val) const /* Finds the longest initial substring in str from position n which is a valid token, and puts the value of the token in val. Returns the length of the token string (i.e., the number of characters read.) It is assumed that the empty string is always a valid token, with value 0, and that this value is characteristic of the empty token. NOTE : initial blank space is ignored. */ { TokenCell *lastfound = d_root; TokenCell *cell = d_root; Ulong q = skipSpaces(str,n); Ulong p = 0; for (Ulong j = 0; j < str.length()-q-n; ++j) { if (cell->left == 0) /* no tokens of bigger length */ goto done; cell = cell->left; char c = str[n+q+j]; while ((cell->right) && (c > cell->letter)) cell = cell->right; if (c == cell->letter) { if (cell->val) { /* longer token found */ lastfound = cell; p = j+1; } } else goto done; } done: val = lastfound->val; q += p; return q; } void TokenTree::insert(const String& str, const Token& val) /* Insert a new string in the tree, corresponding to the token val. */ { TokenCell **icell = &d_root->left; TokenCell *cell = d_root; Ulong j = 0; while (icell[0]) { if (str[j] < icell[0]->letter) /* insertion point found */ break; if (str[j] > icell[0]->letter) { icell = &(icell[0]->right); continue; } /* here str[j] == icell[0]->letter */ cell = icell[0]; icell = &(icell[0]->left); ++j; } for (; j < str.length(); ++j) { cell = new TokenCell; cell->right = icell[0]; /* is zero except maybe the first time */ cell->letter = str[j]; icell[0] = cell; icell = &cell->left; } cell->val = val; return; } }; /**************************************************************************** Chapter VIII -- Input/output functions. This section defines the i/o functions declared in interface.h : - append(str,g,GI) : appends I's representation of g to str; - append(str,f,I) : appends I's representation of the set bits in f to str; - parseCoxWord(P,T,I) : parses a CoxWord using the mintable T; - print(file,g,I) : prints I's representation of g on file; ****************************************************************************/ namespace interface { String& append(String& str, const CoxWord& g, const GroupEltInterface& GI) /* Appends the string g to the string str in the output format defined by I. */ { io::append(str,GI.prefix); for (Ulong j = 0; j < g.length(); ++j) { Generator s = g[j]-1; io::append(str,GI.symbol[s]); if (j+1 < g.length()) /* more to come */ io::append(str,GI.separator); } io::append(str,GI.postfix); return str; } String& append(String& str, const LFlags& f, const Interface& I) /* Appends to str the representation of f as a one-sided descent set, according to the current DescentSetIntrface in I. */ { const DescentSetInterface& d = I.descentInterface(); io::append(str,d.prefix); for (LFlags f1 = f; f1;) { Generator s = bits::firstBit(f1); appendSymbol(str,s,I); f1 &= f1-1; if (f1) /* there is more to come */ io::append(str,d.separator); } io::append(str,d.postfix); return str; } String& appendTwosided(String& str, const LFlags& f, const Interface& I) /* Appends to str the representation of f as a two-sided descent set, according to the current DescentSetIntrface in I. */ { const DescentSetInterface& d = I.descentInterface(); io::append(str,d.twosidedPrefix); for (LFlags f1 = f>>I.rank(); f1;) // left descents { Generator s = bits::firstBit(f1); appendSymbol(str,s,I); f1 &= f1-1; if (f1) /* there is more to come */ io::append(str,d.separator); } io::append(str,d.twosidedSeparator); for (LFlags f1 = f&leqmask[I.rank()-1]; f1;) // right descents { Generator s = bits::firstBit(f1); appendSymbol(str,s,I); f1 &= f1-1; if (f1) /* there is more to come */ io::append(str,d.separator); } io::append(str,d.twosidedPostfix); return str; } void print(FILE *file, const CoxWord& g, const GroupEltInterface& GI) /* Prints the CoxWord g to the file in GI's format. */ { io::print(file,GI.prefix); for (Ulong j = 0; j < g.length(); ++j) { Generator s = g[j]-1; io::print(file,GI.symbol[s]); if (j+1 < g.length()) /* more to come */ io::print(file,GI.separator); } io::print(file,GI.postfix); } void print(FILE *file, const LFlags& f, const DescentSetInterface& DI, const GroupEltInterface& GI) /* Prints f as a one-sided descent set, according to the current DescentSetInterface in I. */ { io::print(file,DI.prefix); for (LFlags f1 = f; f1;) { Generator s = bits::firstBit(f1); io::print(file,GI.symbol[s]); f1 &= f1-1; if (f1) /* there is more to come */ io::print(file,DI.separator); } io::print(file,DI.postfix); return; } void printTwosided(FILE *file, const LFlags& f, const DescentSetInterface& DI, const GroupEltInterface& GI, const Rank& l) /* Prints f as a two-sided descent set, according to the current DescentSetInterface in I. */ { io::print(file,DI.twosidedPrefix); for (LFlags f1 = f>>l; f1;) // left descents { Generator s = bits::firstBit(f1); io::print(file,GI.symbol[s]); f1 &= f1-1; if (f1) /* there is more to come */ io::print(file,DI.separator); } io::print(file,DI.twosidedSeparator); for (LFlags f1 = f&leqmask[l-1]; f1;) // right descents { Generator s = bits::firstBit(f1); io::print(file,GI.symbol[s]); f1 &= f1-1; if (f1) /* there is more to come */ io::print(file,DI.separator); } io::print(file,DI.twosidedPostfix); return; } }; /**************************************************************************** Chapter IX -- Utilities This section provides some utility functions. The following functions are defined : - checkInterface(G) : checks if G has repeated symbols; - checkLeadingWhite(G) : checks if G has symbols starting with whitespace; - checkRepeated(G) : checks if G has repeated symbols; - checkReserved(G,I) : checks if G has reserved symbols w.r.t. I; - descentMaxWidth(I) : maximal width of a one-sided descent set; - isBeginGroup(tok) : tells if tok is begingroup_token; - isContextNbr(tok) : tells if tok is contextnbr_token; - isDenseArray(tok) : tells if tok is densearray_token; - isEndGroup(tok) : tells if tok is endgroup_token; - isInverse(tok) : tells whether tok is inverse_token; - isLongest(tok) : tells whether tok is longest_token; - isModifier(tok) : tells whether tok is of modifier type; - makeSymbols(); - readCoxNbr(P,size) : reads a number off P; - tokenAutomaton(f) : returns a pointer to one of the standard automata; - tokenAutn() (n = 0-7) : standard automata; - tokenType(tok) : defines the type of a token; ****************************************************************************/ namespace interface { const String* checkLeadingWhite(const GroupEltInterface& GI) /* Checks if GI constains a string starting with whitespace, as defined by isspace(). If so, returns a pointer to the first such string; otherwise, returns the null-pointer. */ { if (isspace(GI.prefix[0])) return &GI.prefix; if (isspace(GI.separator[0])) return &GI.separator; if (isspace(GI.postfix[0])) return &GI.postfix; for (Generator s = 0; s < GI.symbol.size(); ++s) { if (isspace(GI.symbol[s][0])) return &GI.symbol[s]; } return 0; } bool checkRepeated(const GroupEltInterface& GI) /* Checks if G has repeated non-empty symbols. NOTE : there could have been some use to allow for prefix = postfix, (e.g. if we envision TeX input with prefix = postfix = $), but it's too late now to do something about that. Such input would have to go through a filter before it could be processed. */ { List l(0); if (GI.prefix.length()) insert(l,GI.prefix); if (find(l,GI.separator) != not_found) return false; if (GI.separator.length()) insert(l,GI.separator); if (find(l,GI.postfix) != not_found) return false; if (GI.separator.length()) insert(l,GI.postfix); for (Generator s = 0; s < GI.symbol.size(); ++s) { if (find(l,GI.symbol[s]) != not_found) return false; if (GI.symbol[s].length()) insert(l,GI.symbol[s]); } return true; } const String* checkReserved(const GroupEltInterface& GI, const Interface& I) /* Checks if GI constains a string that was reserved by I. If so, returns a pointer to the first such string; otherwise, returns the null-pointer. */ { if (I.isReserved(GI.prefix)) return &GI.prefix; if (I.isReserved(GI.separator)) return &GI.separator; if (I.isReserved(GI.postfix)) return &GI.postfix; for (Generator s = 0; s < GI.symbol.size(); ++s) { if (I.isReserved(GI.symbol[s])) return &GI.symbol[s]; } return 0; } Ulong descentWidth(const LFlags& f, const Interface& I) /* Returns the width of the printout of the descent set. We assume that f is either full left, full right or full two-sided descents. */ { String str(0); if (f == leqmask[2*I.rank()-1]) { // two-sided descents interface::appendTwosided(str,f,I); } else { // one-sided descents interface::append(str,leqmask[I.rank()-1],I); } return(str.length()); } bool isBeginGroup(const Token& tok) { return (tok == begingroup_token); } bool isContextNbr(const Token& tok) { return (tok == contextnbr_token); } bool isDenseArray(const Token& tok) { return (tok == densearray_token); } bool isEndGroup(const Token& tok) { return (tok == endgroup_token); } bool isInverse(const Token& tok) { return (tok == inverse_token); } bool isLongest(const Token& tok) { return (tok == longest_token); } bool isModifier(const Token& tok) { return (tokenType(tok) == modifier_type); } bool isPower(const Token& tok) { return (tok == power_token); } }; namespace { void makeSymbols(List& list, const String* const symbol, Ulong n) /* This function deep-copies the n first entries of symbol onto the corresponding entries of list. */ { list.setSize(n); for (Ulong j = 0; j < n; ++j) { list[j].assign(symbol[j]); } return; } }; namespace interface { CoxNbr readCoxNbr(ParseInterface& P, Ulong size) /* This function reads a CoxNbr off P.str, at position P.offset. It returns the number read if it is < size; otherwise it returns undef_coxnbr. Leading white space is ignored. NOTE : we haven't worried about efficiency here. We are not using strtoul because we want to make extra-sure that we know exactly how much of the string is read. */ { String& str = P.str; P.offset += skipSpaces(str,P.offset); Ulong c = 0; Ulong p = 0; Ulong q = P.offset; if ((str[q] == '0') && (str[q+1] == 'x')) { /* process hex number */ p += 2; while (isxdigit(str[q+p])) { CoxNbr x = toCoxNbr(str[q+p]); if (size <= x) /* overflow */ return undef_coxnbr; if (size/16 < c) /* overflow */ return undef_coxnbr; c *= 16; if ((size-x) < c) /* overflow */ return undef_coxnbr; c += x; p++; } } else { /* process decimal number */ while (isdigit(str[q+p])) { CoxNbr x = toCoxNbr(str[q+p]); if (size <= x) /* overflow */ return undef_coxnbr; if (size/10 < c) /* overflow */ return undef_coxnbr; c *= 10; if ((size-x) <= c) /* overflow */ return undef_coxnbr; c += x; p++; } } P.offset+= p; return c; } }; namespace { CoxNbr toCoxNbr(char c) /* This is an implementation of the toint function, which is not guaranteed to exist in ISO C. */ { if (('0' <= c) && (c <= '9')) { return c-'0'; } if (('a' <= c) && (c <= 'f')) { return c-'a'+10; } if (('A' <= c) && (c <= 'F')) { return c-'A'+10; } return 0; } Automaton *tokenAutomaton(LFlags f) { switch(f) { case 0: return tokenAut0(); case 1: return tokenAut1(); case 2: return tokenAut2(); case 3: return tokenAut3(); case 4: return tokenAut4(); case 5: return tokenAut5(); case 6: return tokenAut6(); case 7: return tokenAut7(); default: // unreachable return 0; }; } Automaton *tokenAut0() /* Word recognizer for the case where prefix, postfix and separator are all empty. There should never be tokens of postfix, prefix or generator type. */ { static ExplicitAutomaton aut(2,5); aut.setInitial(0); aut.setFailure(1); aut.setAccept(0); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,0); aut.setTable(0,prefix_type,1); aut.setTable(0,postfix_type,1); aut.setTable(0,separator_type,1); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,1); aut.setTable(1,prefix_type,1); aut.setTable(1,postfix_type,1); aut.setTable(1,separator_type,1); return &aut; } Automaton *tokenAut1() /* Word recognizer for the case where postfix and separator are empty, but prefix is non-empty. */ { static ExplicitAutomaton aut(3,5); aut.setInitial(0); aut.setFailure(2); aut.setAccept(1); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,2); aut.setTable(0,prefix_type,1); aut.setTable(0,postfix_type,2); aut.setTable(0,separator_type,2); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,1); aut.setTable(1,prefix_type,2); // should be 1 ?? aut.setTable(1,postfix_type,2); aut.setTable(1,separator_type,2); aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,2); aut.setTable(2,prefix_type,2); aut.setTable(2,postfix_type,2); aut.setTable(2,separator_type,2); return &aut; } Automaton *tokenAut2() /* Word recognizer for the case where prefix and separator are empty, but postfix is non-empty. */ { static ExplicitAutomaton aut(3,5); aut.setInitial(0); aut.setFailure(2); aut.setAccept(1); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,0); aut.setTable(0,prefix_type,2); aut.setTable(0,postfix_type,1); aut.setTable(0,separator_type,2); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,2); aut.setTable(1,prefix_type,2); aut.setTable(1,postfix_type,2); aut.setTable(1,separator_type,2); aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,2); aut.setTable(2,prefix_type,2); aut.setTable(2,postfix_type,2); aut.setTable(2,separator_type,2); return &aut; } Automaton *tokenAut3() /* Word recognizer for the case where prefix and postfix are non-empty, but separator is empty. */ { static ExplicitAutomaton aut(4,5); aut.setInitial(0); aut.setFailure(3); aut.setAccept(2); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,3); aut.setTable(0,prefix_type,1); aut.setTable(0,postfix_type,3); aut.setTable(0,separator_type,3); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,1); aut.setTable(1,prefix_type,3); aut.setTable(1,postfix_type,2); aut.setTable(1,separator_type,3); aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,3); aut.setTable(2,prefix_type,3); aut.setTable(2,postfix_type,3); aut.setTable(2,separator_type,3); aut.setTable(3,empty_type,3); aut.setTable(3,generator_type,3); aut.setTable(3,prefix_type,3); aut.setTable(3,postfix_type,3); aut.setTable(3,separator_type,3); return &aut; } Automaton *tokenAut4() /* Word recognizer for the case where prefix and postfix are empty, but postfix is non-empty. */ { static ExplicitAutomaton aut(4,5); aut.setInitial(0); aut.setFailure(3); aut.setAccept(0); aut.setAccept(1); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,1); aut.setTable(0,prefix_type,3); aut.setTable(0,postfix_type,3); aut.setTable(0,separator_type,3); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,3); aut.setTable(1,prefix_type,3); aut.setTable(1,postfix_type,3); aut.setTable(1,separator_type,2); aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,1); aut.setTable(2,prefix_type,3); aut.setTable(2,postfix_type,3); aut.setTable(2,separator_type,3); aut.setTable(3,empty_type,3); aut.setTable(3,generator_type,3); aut.setTable(3,prefix_type,3); aut.setTable(3,postfix_type,3); aut.setTable(3,separator_type,3); return &aut; } Automaton *tokenAut5() /* Word recognizer for the case where prefix and separator are non-empty, but postfix is empty. */ { static ExplicitAutomaton aut(5,5); aut.setInitial(0); aut.setFailure(4); aut.setAccept(1); aut.setAccept(2); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,4); aut.setTable(0,prefix_type,1); aut.setTable(0,postfix_type,4); aut.setTable(0,separator_type,4); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,2); aut.setTable(1,prefix_type,4); aut.setTable(1,postfix_type,4); aut.setTable(1,separator_type,4); aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,4); aut.setTable(2,prefix_type,4); aut.setTable(2,postfix_type,4); aut.setTable(2,separator_type,3); aut.setTable(3,empty_type,3); aut.setTable(3,generator_type,2); aut.setTable(3,prefix_type,4); aut.setTable(3,postfix_type,4); aut.setTable(3,separator_type,4); aut.setTable(4,empty_type,4); aut.setTable(4,generator_type,4); aut.setTable(4,prefix_type,4); aut.setTable(4,postfix_type,4); aut.setTable(4,separator_type,4); return &aut; } Automaton *tokenAut6() /* Word recognizer for the case where postfix and separator are non-empty, but prefix is empty. */ { static ExplicitAutomaton aut(5,5); aut.setInitial(0); aut.setFailure(4); aut.setAccept(3); aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,1); aut.setTable(0,prefix_type,4); aut.setTable(0,postfix_type,3); aut.setTable(0,separator_type,4); aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,4); aut.setTable(1,prefix_type,4); aut.setTable(1,postfix_type,3); aut.setTable(1,separator_type,2); aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,1); aut.setTable(2,prefix_type,4); aut.setTable(2,postfix_type,4); aut.setTable(2,separator_type,4); aut.setTable(3,empty_type,3); aut.setTable(3,generator_type,4); aut.setTable(3,prefix_type,4); aut.setTable(3,postfix_type,4); aut.setTable(3,separator_type,4); aut.setTable(4,empty_type,4); aut.setTable(4,generator_type,4); aut.setTable(4,prefix_type,4); aut.setTable(4,postfix_type,4); aut.setTable(4,separator_type,4); return &aut; } Automaton *tokenAut7() /* Word recognizer for the case where prefix, postfix and separator are all non-empty. */ { static ExplicitAutomaton aut(6,5); aut.setInitial(0); aut.setFailure(5); aut.setAccept(4); // initial state; accepts only the prefix aut.setTable(0,empty_type,0); aut.setTable(0,generator_type,5); aut.setTable(0,prefix_type,1); aut.setTable(0,postfix_type,5); aut.setTable(0,separator_type,5); // prefix-read; accepts postfix or generator aut.setTable(1,empty_type,1); aut.setTable(1,generator_type,2); aut.setTable(1,prefix_type,5); aut.setTable(1,postfix_type,4); aut.setTable(1,separator_type,5); // generator-read; accepts postfix or separator aut.setTable(2,empty_type,2); aut.setTable(2,generator_type,5); aut.setTable(2,prefix_type,5); aut.setTable(2,postfix_type,4); aut.setTable(2,separator_type,3); // separator-read; accepts only a generator aut.setTable(3,empty_type,3); aut.setTable(3,generator_type,2); aut.setTable(3,prefix_type,5); aut.setTable(3,postfix_type,5); aut.setTable(3,separator_type,5); // postfix-read; doesn't accept anything aut.setTable(4,empty_type,4); aut.setTable(4,generator_type,5); aut.setTable(4,prefix_type,5); aut.setTable(4,postfix_type,5); aut.setTable(4,separator_type,5); // failure state aut.setTable(5,empty_type,5); aut.setTable(5,generator_type,5); aut.setTable(5,prefix_type,5); aut.setTable(5,postfix_type,5); aut.setTable(5,separator_type,5); return &aut; } }; namespace interface { Letter tokenType(const Token& tok) /* Returns the type of the token : one of generator_type, separator_type, prefix_type, postfix_type. */ { switch (tok) { case 0: return empty_type; case prefix_token: return prefix_type; case postfix_token: return postfix_type; case separator_token: return separator_type; case longest_token: case inverse_token: case power_token: return modifier_type; case begingroup_token: case endgroup_token: return grouping_type; case densearray_token: case contextnbr_token: return number_type; default: return generator_type; }; } }; positivity_final/kl.h0000600000175000017500000002065410011371264016413 0ustar duclouxducloux00000000000000/* This is kl.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef KL_H /* guard against multiple inclusions */ #define KL_H #include "globals.h" #include namespace kl { using namespace globals; }; #include "coxtypes.h" #include "klsupport.h" #include "hecke.h" #include "list.h" #include "polynomials.h" namespace kl { using namespace coxtypes; using namespace hecke; using namespace klsupport; using namespace list; using namespace polynomials; }; /******** type declarations *************************************************/ namespace kl { class KLContext; struct KLStatus; struct MuData; class MuFilter; class KLPol; typedef List KLRow; typedef List MuRow; typedef List > HeckeElt; }; /******** function declarations *********************************************/ #include "bits.h" #include "io.h" #include "list.h" namespace kl { using namespace bits; using namespace io; using namespace list; }; namespace kl { void cBasis(HeckeElt& h, const CoxNbr& y, KLContext& kl); void extractDufloInvolutions(const KLContext& kl, const Partition& pi, BitMap& b); void genericSingularities(HeckeElt& h, const CoxNbr& y, KLContext& kl); void ihBetti(Homology& h, const CoxNbr& y, KLContext& kl); const KLPol& one(); bool isSingular(const HeckeElt& h); bool isSingular(const KLRow& row); void print(FILE* file, const Homology& h); void printMuTable(FILE* file, const KLContext& kl, const Interface& I); void showKLPol(FILE* file, KLContext& kl, const CoxNbr& x, const CoxNbr& y, const Interface& I, const Generator& s = undef_generator); void showMu(FILE* file, KLContext& kl, const CoxNbr& x, const CoxNbr& y, const Interface& I); void sortByPol(KLRow& row); }; /******** type definitions **************************************************/ #include "interface.h" #include "search.h" namespace kl { using namespace coxtypes; using namespace interface; using namespace search; }; namespace kl { class KLPol:public Polynomial { public: static PolynomialType polType() {return KLPOL;} KLPol() {}; KLPol(const Ulong& n):Polynomial(n) {}; KLPol(const KLCoeff& c, const_tag):Polynomial(c,const_tag()) {}; ~KLPol() {}; // KLPol& add(const KLPol& p, const long& n); // KLPol& subtract(const KLPol& p, const MuPol& mp, const Ulong& n); }; struct KLStatus { static const LFlags kl_done = 1L; static const LFlags mu_done = (1L << 1); LFlags flags; Ulong klrows; Ulong klnodes; Ulong klcomputed; Ulong murows; Ulong munodes; Ulong mucomputed; Ulong muzero; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLStatus));} KLStatus(); ~KLStatus(); }; struct MuData { CoxNbr x; KLCoeff mu; Length height; /* constructors */ MuData() {}; MuData(const CoxNbr& d_x, const KLCoeff& d_mu, const Length& d_h) :x(d_x), mu(d_mu), height(d_h) {}; ~MuData() {}; /* comparison */ bool operator> (const MuData& m) const; /* inlined */ }; class MuFilter { private: const SchubertContext& d_p; Length d_l; public: MuFilter(const SchubertContext& p, const Length& l); MuFilter(const SchubertContext& p, const CoxNbr& y); ~MuFilter(); bool operator() (const CoxNbr& x) const; /* inlined */ }; class KLContext { private: KLSupport* d_klsupport; List d_klList; List d_muList; BinaryTree d_klTree; KLStatus* d_status; struct KLHelper; /* provides helper functions */ KLHelper* d_help; friend struct KLHelper; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLContext));} KLContext(KLSupport* kls); ~KLContext(); /* accessors */ const ExtrRow& extrList(const CoxNbr& y) const; /* inlined */ CoxNbr inverse(const CoxNbr& x) const; /* inlined */ const BitMap& involution() const; /* inlined */ bool isExtrAllocated(const CoxNbr& x) const; /* inlined */ bool isFullKL() const; /* inlined */ bool isFullMu() const; /* inlined */ bool isKLAllocated(const CoxNbr& x) const; /* inlined */ bool isMuAllocated(const CoxNbr& x) const; /* inlined */ const KLRow& klList(const CoxNbr& y) const; /* inlined */ const KLSupport& klsupport() const; /* inlined */ Generator last(const CoxNbr& y) const; /* inlined */ const MuRow& muList(const CoxNbr& y) const; /* inlined */ Rank rank() const; /* inlined */ const SchubertContext& schubert() const; /* inlined */ Ulong size() const; /* inlined */ const BinaryTree& tree() const; /* inlined */ /* manipulators */ void applyInverse(const CoxNbr& y); void applyIPermutation(const CoxNbr& y, const Permutation& a);/* inlined */ void clearFullKL(); /* inlined */ void clearFullMu(); /* inlined */ void fillKL(); void fillMu(); const KLPol& klPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator); KLCoeff mu(const CoxNbr& x, const CoxNbr& y); void permute(const Permutation& a); void revertSize(const Ulong& n); void row(HeckeElt& h, const CoxNbr& y); void setFullKL(); /* inlined */ void setFullMu(); /* inlined */ void setSize(const Ulong& n); /* input/output */ // String& append(String& str, const CoxNbr& x) const; void print(FILE* file, const CoxNbr& x, const Interface& I) const; /* inlined */ void printStatus(FILE* file) const; /* to be taken out! */ void compareMu(); }; }; /******** inlined definitions **********************************************/ namespace kl { inline bool MuData::operator> (const MuData& m) const {return x > m.x;} inline bool MuFilter::operator() (const CoxNbr& x) const {Length l = d_p.length(x); return ((d_l-l)%2) && ((d_l-l) > 1);} inline const ExtrRow& KLContext::extrList(const CoxNbr& y) const {return klsupport().extrList(y);} inline CoxNbr KLContext::inverse(const CoxNbr& x) const {return d_klsupport->inverse(x);} inline const BitMap& KLContext::involution() const {return d_klsupport->involution();} inline bool KLContext::isExtrAllocated(const CoxNbr& x) const {return d_klsupport->isExtrAllocated(x);} inline bool KLContext::isFullKL() const {return d_status->flags&KLStatus::kl_done;} inline bool KLContext::isFullMu() const {return d_status->flags&KLStatus::mu_done;} inline bool KLContext::isKLAllocated(const CoxNbr& x) const {return d_klList[x] != 0;} inline bool KLContext::isMuAllocated(const CoxNbr& x) const {return d_muList[x] != 0;} inline const KLRow& KLContext::klList(const CoxNbr& y) const {return *d_klList[y];} inline const KLSupport& KLContext::klsupport() const {return *d_klsupport;} inline Generator KLContext::last(const CoxNbr& y) const {return d_klsupport->last(y);} inline const MuRow& KLContext::muList(const CoxNbr& y) const {return *d_muList[y];} inline Rank KLContext::rank() const {return d_klsupport->rank();} inline const SchubertContext& KLContext::schubert() const {return d_klsupport->schubert();} inline Ulong KLContext::size() const {return d_klList.size();} inline const BinaryTree& KLContext::tree() const {return d_klTree;} inline void KLContext::print(FILE* file, const CoxNbr& x, const Interface& I) const {schubert().print(file,x,I);} inline void KLContext::applyIPermutation(const CoxNbr& y, const Permutation& a) {return rightRangePermute(*d_klList[y],a);} inline void KLContext::clearFullKL() {d_status->flags &= ~KLStatus::kl_done;} inline void KLContext::clearFullMu() {d_status->flags &= ~KLStatus::mu_done;} inline void KLContext::setFullKL() {d_status->flags |= KLStatus::kl_done;} inline void KLContext::setFullMu() {d_status->flags |= KLStatus::mu_done;} }; #endif positivity_final/interface.h0000600000175000017500000003065310011171251017737 0ustar duclouxducloux00000000000000/* This is interface.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef INTERFACE_H /* guard against multiple inclusions */ #define INTERFACE_H #include "globals.h" namespace interface { using namespace globals; }; /******** type declarations *************************************************/ namespace interface { struct DescentSetInterface; struct GroupEltInterface; struct ReservedSymbols; class PolynomialInterface; class Interface; class EmptyInterface; class MinRootInterface; class TokenTree; class TransducerInterface; struct TokenCell; struct ParseInterface; typedef unsigned int Token; // tags struct Hexadecimal {}; struct HexadecimalFromZero {}; struct Decimal {}; struct Alphabetic {}; }; #include "automata.h" #include "coxtypes.h" #include "io.h" #include "list.h" #include "memory.h" #include "minroots.h" #include "transducer.h" namespace interface { using namespace automata; using namespace coxtypes; using namespace list; using namespace minroots; using namespace transducer; }; /******** constants **********************************************************/ namespace interface { const Letter empty_type = 0; const Letter generator_type = 1; const Letter prefix_type = 2; const Letter postfix_type = 3; const Letter separator_type = 4; const Letter modifier_type = 5; const Letter grouping_type = 6; const Letter number_type = 7; }; /******** function declarations **********************************************/ namespace interface { const String* alphabeticSymbols(Ulong n); String& append(String& str, const CoxWord& g, const GroupEltInterface& GI); String& append(String& buf, const LFlags& f, const Interface& I); String& appendSymbol(String& str, const Generator& s, const Interface& I); String& appendTwosided(String& buf, const LFlags& f, const Interface& I); const String* checkLeadingWhite(const GroupEltInterface& GI); bool checkRepeated(const GroupEltInterface& GI); const String* checkReserved(const GroupEltInterface& GI, const Interface& I); const String* decimalSymbols(Ulong n); Ulong descentWidth(const LFlags& f, const Interface& I); const String* hexSymbols(Ulong n); const String* hexSymbolsFromZero(Ulong n); const Permutation& identityOrder(Ulong n); bool isBeginGroup(const Token& tok); bool isContextNbr(const Token& tok); bool isDenseArray(const Token& tok); bool isEndGroup(const Token& tok); bool isInverse(const Token& tok); bool isLongest(const Token& tok); bool isModifier(const Token& tok); bool isPower(const Token& tok); void print(FILE *file, const CoxWord& g, const GroupEltInterface& I); void print(FILE *file, const LFlags& f, const Interface& I); void print(FILE *file, const LFlags& f, const DescentSetInterface& DI, const GroupEltInterface& GI); void printSymbol(FILE *file, const Generator& s, const Interface& I); void printTwosided(FILE *file, const LFlags& f, const DescentSetInterface& DI, const GroupEltInterface& GI, const Rank& l); void printTwosided(FILE *file, const LFlags& f, const Interface& I); /* inlined */ CoxNbr readCoxNbr(ParseInterface& P, Ulong size); Letter tokenType(const Token& tok); const String* twohexSymbols(Ulong n); }; /******** type definitions ***************************************************/ namespace interface { struct ParseInterface { String str; Ulong nestlevel; List a; CoxWord c; State x; Ulong offset; /* constructors and destructors */ ParseInterface(); ~ParseInterface(); void reset(); }; struct TokenCell { Token val; char letter; TokenCell *left; TokenCell *right; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TokenCell));} TokenCell() {}; ~TokenCell(); }; class TokenTree { private: TokenCell *d_root; public: /* constructors and destructors */ TokenTree(); TokenTree(TokenCell *cell):d_root(cell) {}; ~TokenTree(); /* manipulators */ void insert(const String& str, const Token& val); /* accessors */ Ulong find(String& str, Token& val) const; Ulong find(const String& str, const Ulong& n, Token& val) const; TokenCell *root() {return d_root;} }; struct DescentSetInterface { String prefix; String postfix; String separator; String twosidedPrefix; String twosidedPostfix; String twosidedSeparator; void* operator new(size_t size) {return arena().alloc(size);} void* operator new(size_t size, void* ptr) {return ptr;} void operator delete(void* ptr) {return arena().free(ptr,sizeof(DescentSetInterface));} void operator delete(void* p1, void* p2) {}; DescentSetInterface(); DescentSetInterface(GAP); ~DescentSetInterface(); void setPostfix(const String& str); void setPrefix(const String& str); void setSeparator(const String& str); void setTwosidedPrefix(const String& str); void setTwosidedPostfix(const String& str); void setTwosidedSeparator(const String& str); }; struct GroupEltInterface { List symbol; String prefix; String postfix; String separator; void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GroupEltInterface));} #if 0 void* operator new(size_t size, void* ptr) {return ptr;} void operator delete(void* p1, void* p2) {}; #endif GroupEltInterface(); GroupEltInterface(const Rank& l); GroupEltInterface(const Rank& l, Alphabetic); GroupEltInterface(const Rank& l, Decimal); GroupEltInterface(const Rank& l, GAP); GroupEltInterface(const Rank& l, Hexadecimal); GroupEltInterface(const Rank& l, HexadecimalFromZero); ~GroupEltInterface(); void setPostfix(const String& a); void setPrefix(const String& a); void setSeparator(const String& a); void setSymbol(const Generator& s, const String& a); void print(FILE* file) const; }; struct ReservedSymbols { String beginGroup; String endGroup; String longest; String inverse; String power; String contextnbr; String densearray; ReservedSymbols(); ReservedSymbols(Default); ~ReservedSymbols(); }; class Interface { protected: Permutation d_order; TokenTree d_symbolTree; Automaton const* d_tokenAut; GroupEltInterface* d_in; GroupEltInterface* d_out; DescentSetInterface* d_descent; String d_beginGroup; String d_endGroup; String d_longest; String d_inverse; String d_power; String d_contextNbr; String d_denseArray; String d_parseEscape; List d_reserved; Rank d_rank; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(Interface));} Interface(const Type& x, const Rank& l); virtual ~Interface(); /* manipulators */ void readSymbols(); void setAutomaton(); void setDescent(Default); void setDescent(GAP); virtual void setIn(const GroupEltInterface& i); /* inlined */ void setInPostfix(const String& a); /* inlined */ void setInPrefix(const String& a); /* inlined */ void setInSeparator(const String& a); /* inlined */ void setInSymbol(const Generator& s, const String& a); /* inlined */ void setOrder(const Permutation& gen_order); virtual void setOut(const GroupEltInterface& i); /* inlined */ void setOutPostfix(const String& a); /* inlined */ void setOutPrefix(const String& a); /* inlined */ void setOutSeparator(const String& a); /* inlined */ void setOutSymbol(const Generator& s, const String& a); /* inlined */ /* accessors */ const DescentSetInterface& descentInterface() const; /* inlined */ Ulong getToken(ParseInterface& P, Token& tok) const; /* inlined */ Ulong in(const Ulong& j) const; /* inlined */ const GroupEltInterface& inInterface() const; /* inlined */ const String& inPostfix() const; /* inlined */ const String& inPrefix() const; /* inlined */ const String& inSeparator() const; /* inlined */ const String& inSymbol(const Generator& s) const; /* inlined */ bool isReserved(const String& str) const; /* inlined */ const Permutation& order() const; /* inlined */ Ulong out(const Ulong& j) const; /* inlined */ const GroupEltInterface& outInterface() const; /* inlined */ const String& outPostfix() const; /* inlined */ const String& outPrefix() const; /* inlined */ const String& outSeparator() const; /* inlined */ const String& outSymbol(const Generator& s) const; /* inlined */ bool parseCoxWord(ParseInterface& P, const MinTable& T) const; Rank rank() const; /* inlined */ bool readCoxElt(ParseInterface& P) const; const TokenTree& symbolTree() const; // i/o virtual String& append(String& str, const CoxWord& g) const; virtual void print(FILE* file, const CoxWord& g) const; }; }; /******** inline implementations *******************************************/ namespace interface { inline String& append(String& str, const CoxWord& g, const Interface& I) {return append(str,g,I.outInterface());} inline String& appendSymbol(String& str, const Generator& s, const Interface& I) {return io::append(str,I.outSymbol(s));} inline void print(FILE *file, const LFlags& f, const Interface& I) {return print(file,f,I.descentInterface(),I.outInterface());} inline void printSymbol(FILE *file, const Generator& s, const Interface& I) {io::print(file,I.outSymbol(s));} inline void printTwosided(FILE *file, const LFlags& f, const Interface& I) {return printTwosided(file,f,I.descentInterface(),I.outInterface(), I.rank());} inline Ulong TokenTree::find(String& str, Token& val) const {return find(str.ptr(),str.length(),val);} inline const DescentSetInterface& Interface::descentInterface() const {return *d_descent;} inline Ulong Interface::getToken(ParseInterface& P, Token& tok) const {return d_symbolTree.find(P.str,P.offset,tok);} inline const GroupEltInterface& Interface::inInterface() const {return *d_in;} inline const String& Interface::inPostfix() const {return d_in->postfix;} inline const String& Interface::inPrefix() const {return d_in->prefix;} inline const String& Interface::inSeparator() const {return d_in->separator;} inline const String& Interface::inSymbol(const Generator& s) const {return d_in->symbol[s];} inline bool Interface::isReserved(const String& str) const {return find(d_reserved,str) != ~static_cast(0);} inline const GroupEltInterface& Interface::outInterface() const {return *d_out;} inline const Permutation& Interface::order() const {return d_order;} inline const String& Interface::outPostfix() const {return d_out->postfix;} inline const String& Interface::outPrefix() const {return d_out->prefix;} inline const String& Interface::outSeparator() const {return d_out->separator;} inline const String& Interface::outSymbol(const Generator& s) const {return d_out->symbol[s];} inline Rank Interface::rank() const {return d_rank;} inline const TokenTree& Interface::symbolTree() const {return d_symbolTree;} inline void Interface::setInPostfix(const String& a) {d_in->setPostfix(a);} inline void Interface::setInPrefix(const String& a) {d_in->setPrefix(a);} inline void Interface::setInSeparator(const String& a) {d_in->setSeparator(a);} inline void Interface::setInSymbol(const Generator& s, const String& a) {return d_in->setSymbol(s,a);} inline void Interface::setOutPostfix(const String& a) {d_out->setPostfix(a);} inline void Interface::setOutPrefix(const String& a) {d_out->setPrefix(a);} inline void Interface::setOutSeparator(const String& a) {d_out->setSeparator(a);} inline void Interface::setOutSymbol(const Generator& s, const String& a) {return d_out->setSymbol(s,a);} inline String& Interface::append(String& str, const CoxWord& g) const {return interface::append(str,g,*d_out);} inline void Interface::print(FILE* file, const CoxWord& g) const {interface::print(file,g,*d_out);} }; #endif positivity_final/invkl.cpp0000600000175000017500000011374110012720003017451 0ustar duclouxducloux00000000000000/* This is invkl.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "invkl.h" /* This module contains code for the computation of _inverse_ Kazhdan-Lusztig polynomials. For infinite groups, they are probably more significant than the ordinary ones; for finite groups of course it is always possible to move from one to the other using the longest element. The inverse k-l polynomial Q_{x,y} is just the Stanley polynomial for the interval [x,y]^o (dual to [x,y]), corresponding to the usual R-function on [x,y]. Therefore, it may be computed via an induction procedure quite similar to the one used for ordinary k-l polynomials : - first, we extremalize the pair; this means taking y as far down as it will go under the up-set of x, until we reach a situation where the up-set of x is contained in the up-set of y, or equivalently LR(y) contained in LR(x) (so in fact these are the usual extremal pairs, the difference being that we move y instead of moving x.) - then, we apply recursion : let s be s.t. ys < y, so that also xs < x; then we have : Q_{xs,ys} = Q_{x,y} + qQ_{x,ys} - \sum_z Q_{ys,z}mu(x,z)q^{1/2(l_z-l_xs)} where z runs through the elements in [x,ys] s.t. the length difference with x is odd and zs > z. From this we get Q_{x,y} in terms of Q's with a shorter y. It seems that here it is not so easy to localize the computation on any given row. Therefore, we only offer two modes of computation : the computation of a single polynomial, where only the ingredients that actually come up are computed, or the computation of all polynomials P_{x,y} for x <= y in a given interval [e,w]. */ namespace invkl { struct KLContext::KLHelper { /* data */ KLContext* d_kl; /* constructors and destructors */ KLHelper(KLContext* kl):d_kl(kl) {}; ~KLHelper() {}; void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLHelper));} /* member functions */ void addCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, KLPol& pol); void allocExtrRow(const CoxNbr& y) {klsupport().allocExtrRow(y);} void allocKLRow(const CoxNbr& y); void allocMuRow(const CoxNbr& y); void allocRowComputation(const CoxNbr& y); bool checkKLRow(const CoxNbr& y); bool checkMuRow(const CoxNbr& y); void coatomCorrection(const CoxNbr& y, List& pol); KLCoeff computeMu(const CoxNbr& x, const CoxNbr& y); const ExtrRow& extrList(const CoxNbr& y) {return klsupport().extrList(y);} const KLPol* fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator); void fillKLRow(const CoxNbr& y); void initWorkspace(const CoxNbr& y, List& pol); CoxNbr inverse(const CoxNbr& y) {return klsupport().inverse(y);} void inverseMuRow(const CoxNbr& y); bool isExtrAllocated(const CoxNbr& y) {return klsupport().isExtrAllocated(y);} bool isKLAllocated(const CoxNbr& y) {return d_kl->isKLAllocated(y);} bool isMuAllocated(const CoxNbr& y) {return d_kl->isMuAllocated(y);} KLRow& klList(const CoxNbr& y) {return *d_kl->d_klList[y];} const KLPol& klPol(const CoxNbr& x, const CoxNbr& y) {return d_kl->klPol(x,y);} KLSupport& klsupport() {return d_kl->d_klsupport[0];} search::BinaryTree& klTree() {return d_kl->d_klTree;} Generator last(const CoxNbr& x) {return klsupport().last(x);} void lastTerm(const CoxNbr& y, List& pol); void makeKLRow(const CoxNbr& y); void muCorrection(const CoxNbr& y, List& pol); MuRow& muList(const CoxNbr& y) {return *d_kl->d_muList[y];} Rank rank() {return d_kl->rank();} void readMuRow(const CoxNbr& y); KLCoeff recursiveMu(const CoxNbr& x, const CoxNbr& y, const Generator& s); const SchubertContext& schubert() {return klsupport().schubert();} KLStatus& status() {return *d_kl->d_status;} void writeKLRow(const CoxNbr& y, List& pol); }; }; namespace { using namespace invkl; MuData* find(MuRow& row, const CoxNbr& x); const KLPol& zeroPol(); }; /***************************************************************************** Chapter I -- The KLContext class. The KLContext for inverse polynomials is formally identical to the one for ordinary polynomials. We have chosen to keep the organization in rows, where a row means the extremal x <= y, for a given y, even if perhaps in this case it would be natural to fix x and let y vary; one reason is that in general there would be infinitely many such y ... The following functions are defined : - constructors and destructors : - KLContext(KLSupport* kls); - ~KLContext(); - accessors : - manipulators : - applyInverse(const CoxNbr&) : exchanges rows for x and x_inverse in kl_list; - fillKL() : fills the full k-l table; - fillMu() : fills the full mu-table; - klPol(x,y) : returns the k-l polynomial P_{x,y}; - permute(const Permutation&) : applies a permutation to the context; - reverseSize(const Ulong&) : reverts to a previous size; - setSize(const Ulong&) : sets the context to a larger size; *****************************************************************************/ namespace invkl { KLContext::KLContext(KLSupport* kls) :d_klsupport(kls), d_klList(kls->size()), d_muList(kls->size()) { d_status = new KLStatus; d_help = new KLHelper(this); d_klList.setSizeValue(kls->size()); d_klList[0] = new KLRow(1); d_klList[0]->setSizeValue(1); d_klList[0][0][0] = d_klTree.find(one()); d_status->klnodes++; d_status->klrows++; d_status->klcomputed++; d_muList.setSizeValue(kls->size()); d_muList[0] = new MuRow(0); } KLContext::~KLContext() /* The destructions that are not done automatically are those of he various kl- and mu-lists, and of the status. The support should not be destroyed, as it may be shared with other kl contexts. */ { for (Ulong j = 0; j < size(); ++j) { delete d_klList[j]; delete d_muList[j]; } delete d_status; return; } /******** accessors **********************************************************/ /******** manipulators *******************************************************/ void KLContext::applyInverse(const CoxNbr& x) /* Exchanges rows for x and x_inverse in klList. It is assumed that the row for x_inverse is allocated. */ { CoxNbr xi = inverse(x); d_klList[x] = d_klList[xi]; d_klList[xi] = 0; } void KLContext::fillKL() /* This function fills all the rows in klList, in a straightforward way (and all the mu-rows as well.) */ { if (isFullKL()) return; for (CoxNbr y = 0; y < size(); ++y) { if (inverse(y) < y) { d_help->inverseMuRow(inverse(y)); continue; } if (!isKLAllocated(y)) d_help->allocKLRow(y); d_help->fillKLRow(y); if (ERRNO) { Error(ERRNO); ERRNO = ERROR_WARNING; return; } d_help->readMuRow(y); if (ERRNO) { Error(ERRNO); ERRNO = ERROR_WARNING; return; } } setFullKL(); return; } void KLContext::fillMu() /* This function fills all the rows in the mu-list, in a straightforward way. Sets the error ERROR_WARNING in case of error. NOTE : error handling should be improved! */ {} const KLPol& KLContext::klPol(const CoxNbr& d_x, const CoxNbr& d_y, const Generator& s) /* This function returns the Kazhdan-Lusztig polynomial P_{x,y}. It is assumed that the condition x <= y has already been checked, and that x and y are valid context numbers. */ { CoxNbr x = d_x; CoxNbr y = d_y; const SchubertContext& p = schubert(); /* put y in extremal position w.r.t. x */ y = p.minimize(y,p.ascent(x)); /* check for trivial cases */ if (p.length(y) - p.length(x) < 3) { /* result is 1 */ return one(); } /* go to inverses if necessary */ if (inverse(y) < y) { y = inverse(y); x = inverse(x); } /* check if klList[y] is allocated */ if (!isKLAllocated(y)) { d_help->allocKLRow(y); if (ERRNO) return zeroPol(); } /* find x in extrList[y] */ Ulong m = find(extrList(y),x); const KLPol*& pol = d_help->klList(y)[m]; if (pol == 0) { /* we have to compute the polynomial */ pol = d_help->fillKLPol(x,y,s); if (ERRNO) return zeroPol(); } return *pol; } KLCoeff KLContext::mu(const CoxNbr& x, const CoxNbr& y, const Generator& s) /* This function returns the mu-coefficient mu(x,y). It is assumed that the condition x <= y has already been checked, and that x and y are valid context numbers. The return value is zero if the length difference is even. If an error occurs, it forwards the error value and returns the value undef_klcoeff for mu. */ { const SchubertContext& p = schubert(); Length d = p.length(y) - p.length(x); if (d%2 == 0) return 0; if (d == 1) /* x is a coatom of y */ return 1; /* check if x is in extremal position w.r.t. y */ if (y != p.minimize(y,p.ascent(x))) return 0; /* allocate *d_muList[y] if necessary */ if (!isMuAllocated(y)) { d_help->allocMuRow(y); if (ERRNO) return undef_klcoeff; } /* find x in muList(y) */ MuRow& m = d_help->muList(y); MuData* md = find(m,x); if (md == 0) return 0; if (md->mu == undef_klcoeff) { /* we need to compute the coefficient */ md->mu = d_help->computeMu(x,y); if (ERRNO) return undef_klcoeff; } return md->mu; } void KLContext::permute(const Permutation& a) /* Permutes the context according to the permutation a. See the permute function in kl.cpp for a full description. The idea is that a[x] is the new number of the element previously numbered x : new[a[x]] = old[x]. */ { /* permute values */ for (CoxNbr y = 0; y < size(); ++y) { if (!isMuAllocated(y)) continue; MuRow& row = *d_muList[y]; for (Ulong j = 0; j < row.size(); ++j) row[j].x = a[row[j].x]; row.sort(); } /* permute ranges */ BitMap b(a.size()); for (CoxNbr x = 0; x < size(); ++x) { if (b.getBit(x)) continue; if (a[x] == x) { b.setBit(x); continue; } for (CoxNbr y = a[x]; y != x; y = a[y]) { /* back up values for y */ KLRow* kl_buf = d_klList[y]; MuRow* mu_buf = d_muList[y]; /* put values for x in y */ d_klList[y] = d_klList[x]; d_muList[y] = d_muList[x]; /* store backup values in x */ d_klList[x] = kl_buf; d_muList[x] = mu_buf; /* set bit*/ b.setBit(y); } b.setBit(x); } return; } void KLContext::revertSize(const Ulong& n) /* Reverts the sizes of the lists to size n. This is meant to be used only immediately after a failing context extension, to preserve the consistency of the various list sizes. In particular, it will fail miserably if a premutation has taken place in-between. */ { d_klList.setSize(n); d_muList.setSize(n); return; } void KLContext::row(HeckeElt& h, const CoxNbr& y) /* This function returns in h the data for the full row of y in the k-l table, sorted in the context number order. NOTE : this is probably not the natural concept of row in the context of inverse k-l polynomials, but it's the only one that's reasonably implementable, so we'll keep it anyway. */ { if (!d_help->checkKLRow(y)) { d_help->makeKLRow(y); } if (ERRNO) { Error(ERRNO); ERRNO = ERROR_WARNING; return; } if (y <= inverse(y)) { const ExtrRow& e = extrList(y); h.setSize(e.size()); const KLRow& klr = klList(y); for (Ulong j = 0; j < e.size(); ++j) { h[j].setData(e[j],klr[j]); } } else { /* go over to inverses */ CoxNbr yi = inverse(y); const ExtrRow& e = extrList(yi); h.setSize(e.size()); const KLRow& klr = klList(yi); for (Ulong j = 0; j < e.size(); ++j) { h[j].setData(inverse(e[j]),klr[j]); } h.sort(); /* make sure list is ordered */ } return; } void KLContext::setSize(const Ulong& n) { CoxNbr prev_size = size(); CATCH_MEMORY_OVERFLOW = true; d_klList.setSize(n); if (ERRNO) goto revert; d_muList.setSize(n); if (ERRNO) goto revert; CATCH_MEMORY_OVERFLOW = false; clearFullKL(); clearFullMu(); return; revert: CATCH_MEMORY_OVERFLOW = false; revertSize(prev_size); return; } }; /**************************************************************************** Chapter II -- The KLHelper class The purpose of the KLHelper class is to hide from the public eye a number of helper functions, used in the construction and maintenance of the k-l context. This unclutters kl.h quite a bit. The following functions are defined : - addCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, KLPol& pol) : ads the corrections for mu and coatoms; - allocKLRow(const CoxNbr& y) : allocates a row in the k-l list; - allocRowComputation(const CoxNbr& y) : initial allocation for a row-computation - checkKLRow(const CoxNbr& y) : checks if a k-l row is fully computed; - coatomCorrection(const CoxNbr& y, List& pol) : subtracts the terms ofr coatoms in the mu-correction, for a full row; - computeMu(const CoxNbr& x, const CoxNbr& y) : computes a mu-coefficient; - fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator) : fills in one polynomial, using s as descent; - fillKLRow(const CoxNbr& y) : fills in one row in the k-l table; CoxNbr inverse(const CoxNbr& y) : returns the inverse of y; - initWorkspace(const CoxNbr& y, List& pol) : another preliminary to the computation of a row; - inverseMuRow(const CoxNbr& y) : constructs the mu-row for y from that of the inverse of y; - lastTerm(const CoxNbr& y, List& pol) : takes care of the last term P_{x,ys} in the computation of a full row; - muCorrection(const CoxNbr& y, List& pol) : subtracts the non-coatom mu-part in the computation of a row; - readMuRow(const CoxNbr& y) : fills in the mu-row from the k-l row; - writeKLRow(const CoxNbr& y, List& pol) : transfers the polynomials from pol to klList; ****************************************************************************/ namespace invkl { void KLContext::KLHelper::addCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, KLPol& pol) /* This function adds the correcting terms both for atoms of x and for the other mu-coefficients. We do this in one pass, so that we don't have to go twice through the expensive extraction of the interval [x,ys]. We have to assume that CATCH_MEMORY_OVERFLOW may be set. Forwards the error ERROR_WARNING in case of error. */ { const SchubertContext& p = schubert(); CoxNbr ys = p.shift(y,s); BitMap b(0); p.extractClosure(b,ys); b.andnot(p.downset(s)); // extract z s.t. zs > z b.andnot(p.parity(x)); // extract elements with opposite length parity from x BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; if (!p.inOrder(x,z)) continue; if (p.length(z)-p.length(x) == 1) { // x is a coatom of z const KLPol& p_zys = klPol(z,ys); if (ERRNO) goto abort; pol.add(p_zys,1,1); continue; } // if we get here l(z)-l(x) >= 3 KLCoeff mu_xz = d_kl->mu(x,z); if (ERRNO) goto abort; if (mu_xz == 0) continue; const KLPol& p_zys = klPol(z,ys); if (ERRNO) goto abort; Ulong h = (p.length(z)-p.length(x)+1)/2; pol.add(p_zys,mu_xz,h); continue; } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::allocKLRow(const CoxNbr& y) /* This function allocates one row of the kl_list. The row contains one entry for each x <= y which is extremal w.r.t. the descent set of y. The algorithm is as follows : we extract the interval [e,y] as a bitmap, extremalize it by intersecting with the downsets for the various generators, and read it into the row. Forwards the error MEMORY_WARNING if there is a memory overflow and CATCH_MEMORY_OVERFLOW is turned on. */ { if (!isExtrAllocated(y)) allocExtrRow(y); Ulong n = extrList(y).size(); d_kl->d_klList[y] = new KLRow(n); if (ERRNO) return; klList(y).setSizeValue(n); status().klnodes += n; status().klrows++; return; } void KLContext::KLHelper::allocMuRow(const CoxNbr& y) /* This function allocates one row in the muList. There is one entry for each x < y which is extremal w.r.t. y, and has odd length-difference > 1 with y. As with allocKLRow, this function is not designed for maximal efficiency; row allocations for big computations should be handled differently. */ { const SchubertContext& p = schubert(); BitMap b(0); p.extractClosure(b,y); maximize(p,b,p.descent(y)); b.andnot(p.parity(y)); // extract elements with opposite parity from y const CoatomList& c = p.hasse(y); for (Ulong j = 0; j < c.size(); ++j) { // remove coatoms b.clearBit(c[j]); } d_kl->d_muList[y] = new MuRow(0); BitMap::Iterator b_end = b.end(); Length ly = p.length(y); for (BitMap::Iterator k = b.begin(); k != b_end; ++k) { CoxNbr x = *k; Length h = (ly-p.length(x)-1)/2; MuData md(x,undef_klcoeff,h); muList(y).append(md); } return; } void KLContext::KLHelper::allocRowComputation(const CoxNbr& y) /* This function does the memory allocation for the computation of a full row in the context. Since this means that we have to fill all rows for z <= y, all these are allocated. For now, this is implemented in a straightforward manner. */ { const SchubertContext& p = schubert(); BitMap b(0); p.extractClosure(b,y); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; if (inverse(z) < z) continue; if (!isExtrAllocated(z)) { klsupport().allocExtrRow(z); if (ERRNO) return; } if (!isKLAllocated(z)) { const ExtrRow& e = extrList(z); d_kl->d_klList[z] = new KLRow(0); klList(z).setSize(e.size()); if (ERRNO) return; } } return; } bool KLContext::KLHelper::checkKLRow(const CoxNbr& d_y) /* This function checks if the row for y (or for inverse(y) if appropriate) in klList has been filled. */ { CoxNbr y = d_y; if (inverse(y) < y) y = inverse(y); if (!isKLAllocated(y)) /* row is not allocated */ return false; KLRow& kl_row = klList(y); for (Ulong j = 0; j < kl_row.size(); ++j) { if (kl_row[j] == 0) return false; } return true; } bool KLContext::KLHelper::checkMuRow(const CoxNbr& y) /* This function checks if the row for y in muList has been filled. */ { if (!isMuAllocated(y)) /* row is not allocated */ return false; const MuRow& mu_row = muList(y); for (Ulong j = 0; j < mu_row.size(); ++j) { if (mu_row[j].mu == undef_klcoeff) return false; } return true; } void KLContext::KLHelper::coatomCorrection(const CoxNbr& y, List& pol) /* This function adds the correction terms corresponding to the atoms of x in [x,y]. What we really do, in fact, is run through the set of z <= y, for each z look at the coatoms of z, and see which are extremal w.r.t. y. This is certainly quite a bit more cumbersome than the procedure for ordinary k-l polynomials, but I haven't a better idea just yet. */ { const SchubertContext& p = schubert(); BitMap b(0); Generator s = last(y); CoxNbr ys = p.shift(y,s); p.extractClosure(b,ys); b.andnot(p.downset(s)); LFlags fy = p.descent(y); const ExtrRow& e = extrList(y); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; const CoatomList& c = p.hasse(z); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr x = c[j]; LFlags fx = p.descent(x); if ((fx & fy) != fy) // x is not extremal w.r.t. y continue; /* find x in the extremal list */ Ulong k = find(e,x); /* add q*P_{z,ys} to pol[k] */ pol[k].add(klPol(z,ys),1,1); if (ERRNO) { Error(ERRNO,x,y); goto abort; } } } return; abort: ERRNO = ERROR_WARNING; return; } KLCoeff KLContext::KLHelper::computeMu(const CoxNbr& x, const CoxNbr& y) /* This function gets a previously uncomputed entry in the muList. It is based on the following remark (essentially Lusztig's "star-operation" situation). We already assume that LR(x) contains LR(y). Now let s be in LR(y), such that LR(ys) is _not_ contained in LR(x) (such an s exists iff LR(x) does not contain twoDescent(y).) Then let t be in LR(ys), not in LR(x) (and hence not in LR(y)). Then it must be so that s and t do not commute; in particular they act on the same side; assume this is on the right. So we have yst < ys < y < yt, xs < x < xt. Assume that x <= ys (otherwise mu(x,y) = mu(xs,ys)). Then from the fact that xt > x, yst < ys, exactly as in the proof of thm. 4.2. in the original k-l paper, one sees that at most four terms survive in the recursion formula : we have mu(x,y) = mu(xs,ys) - mu(x,yst) + mu(xt,ys)(if xts > xt) + mu(x,yst)(if ysts > yst) So in all these cases we get an elementary recursion. Sets the error MU_FAIL, and returns the value undef_klcoeff, in case of failure (this can be due to memory overflow, or to coefficient over- or underflow.) */ { if (inverse(y) < y) return computeMu(inverse(x),inverse(y)); const SchubertContext& p = schubert(); LFlags f = p.twoDescent(y); if ((p.descent(x)&f) == f) { /* x is super-extremal w.r.t. y */ return recursiveMu(x,y,last(y)); } Generator s, t; /* choose s s.t. LR(ys) not contained in LR(x) */ for (LFlags f1 = p.descent(y); f1; f1 &= f1-1) { Generator u = firstBit(f1); CoxNbr yu = p.shift(y,u); LFlags fu = p.descent(yu); if ((p.descent(x)&fu) != fu) { s = u; t = firstBit(fu & ~p.descent(x)); break; } } CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); KLCoeff r1 = d_kl->mu(xs,ys); if (ERRNO) goto abort; if (!p.inOrder(x,ys)) { /* value is found */ status().mucomputed++; if (r1 == 0) status().muzero++; return r1; } { CoxNbr xt = p.shift(x,t); CoxNbr yst = p.shift(ys,t); if (!p.isDescent(xt,s)) { // add mu(xt,ys) KLCoeff r = d_kl->mu(xt,ys); if (ERRNO) goto abort; safeAdd(r1,r); if (ERRNO) goto abort; } if (!p.isDescent(yst,s)) { // add mu(x,yst) KLCoeff r = d_kl->mu(x,yst); if (ERRNO) goto abort; safeAdd(r1,r); if (ERRNO) goto abort; } { KLCoeff r = d_kl->mu(x,yst); if (ERRNO) goto abort; safeSubtract(r1,r); if (ERRNO) goto abort; } return r1; } abort: if (ERRNO != MEMORY_WARNING) ERRNO = MU_FAIL; return undef_klcoeff; } const KLPol* KLContext::KLHelper::fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& d_s) /* This function fills in a single k-l polynomial. In this function our goal is not speed, but rather computing as few things as possible. So only the terms that actually do come up in the recursion are computed. On the other hand, when a row in the klList or in the muList is allocated, it has to be allocated in full, so there is some amount of waste there. It is assumed that x <= y has already been checked, that inverse(y) >= y, and that klList[y] is allocated as well. Returns 0 in case of error, and sets the error KL_FAIL. */ { const SchubertContext& p = schubert(); /* check easy cases */ Length l = p.length(y) - p.length(x); if (l < 3) { status().klcomputed++; return &(one()); } Generator s = d_s; /* If d_s is undef_generator, we compute the polynomial using descent by last term in normal form */ if (s == undef_generator) s = last(y); CoxNbr ys = p.shift(y,s); CoxNbr xs = p.shift(x,s); /* check if x is comparable to ys */ if (!p.inOrder(x,ys)) { /* return the answer recursively */ status().klcomputed++; return &klPol(xs,ys); } CATCH_MEMORY_OVERFLOW = true; /* initialize the workspace to P_{xs,ys} */ KLPol pol = klPol(xs,ys); if (ERRNO) goto abort; /* add correction terms */ addCorrection(x,y,s,pol); if (ERRNO) goto abort; /* subtract q.P_{x,ys} */ { const KLPol& p_xys = klPol(x,ys); if (ERRNO) goto abort; pol.subtract(p_xys,1); } /* find address of polynomial */ { const KLPol* p_xy = klTree().find(pol); if (ERRNO) goto abort; return p_xy; } abort: /* an error occurred */ CATCH_MEMORY_OVERFLOW = false; // something should be done here about the error! especially in case // MEMORY_WARNING. ERRNO = KL_FAIL; return 0; } void KLContext::KLHelper::fillKLRow(const CoxNbr& d_y) /* This function fills in the row for d_y in d_klList. It assumes that all the rows for z < d_y are already filled. */ { static List pol(0); CoxNbr y = d_y; if (y == 0) return; if (inverse(y) < y) /* nothing to do */ return; /* prepare workspace; pol holds the row of polynomials; initialize workspace with P_{xs,ys} */ initWorkspace(y,pol); /* add correcting terms */ muCorrection(y,pol); if (ERRNO) goto abort; coatomCorrection(y,pol); if (ERRNO) goto abort; /* subtract q.P_{xs,y} when appropriate */ lastTerm(y,pol); if (ERRNO) goto abort; /* write down result */ writeKLRow(y,pol); if (ERRNO) goto abort; return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::initWorkspace(const CoxNbr& y, List& pol) /* This function sets pol to a row of one polynomial for each x in klList(y), and initializes the corresponding pol[j] to klPol(xs,ys). */ { const SchubertContext& p = schubert(); const ExtrRow& e = extrList(y); pol.setSize(e.size()); if (ERRNO) goto abort; /* initialize with values P_{xs,ys} */ { Generator s = last(y); CoxNbr ys = p.rshift(y,s); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr xs = p.shift(e[j],s); pol[j] = klPol(xs,ys); if (ERRNO) goto abort; } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::inverseMuRow(const CoxNbr& y) /* This function constructs the mu-row for the inverse of y from that of y. It is assumed that the row for inverse(y) is filled in, and that y is not equal to its inverse. We delete the row for y, since it will be faster to reconstruct it in any case than to extract the non-computed values from the inverse list. */ { CoxNbr yi = inverse(y); if (isMuAllocated(yi)) { /* deallocate; update status */ MuRow& m = muList(yi); for (Ulong j = 0; j < m.size(); ++j) { KLCoeff mu = m[j].mu; if (mu != undef_klcoeff) status().mucomputed--; if (mu == 0) status().muzero--; } status().munodes -= m.size(); delete &m; } d_kl->d_muList[yi] = new MuRow(muList(y)); MuRow& m = muList(yi); for (Ulong j = 0; j < m.size(); ++j) { m[j].x = inverse(m[j].x); } m.sort(); /* update status */ for (Ulong j = 0; j < m.size(); ++j) { KLCoeff mu = m[j].mu; if (mu != undef_klcoeff) status().mucomputed++; if (mu == 0) status().muzero++; } status().munodes += m.size(); return; } void KLContext::KLHelper::lastTerm(const CoxNbr& y, List& pol) /* This function subtracts the term .qP_{x,ys} from the term pol[j] corresponding to x. We do this last, so that an alert can be given for negative coefficients. */ { const SchubertContext& p = schubert(); Generator s = last(y); CoxNbr ys = schubert().shift(y,s); BitMap b(0); p.extractClosure(b,ys); maximize(p,b,p.descent(y)); const ExtrRow& e = extrList(y); BitMap::Iterator b_end = b.end(); Ulong j = 0; for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr x = *i; while (e[j] < x) // move e[j] up to x ++j; pol[j].subtract(klPol(x,ys),1); if (ERRNO) { Error(ERRNO,x,y); ERRNO = ERROR_WARNING; return; } ++j; } return; } void KLContext::KLHelper::makeKLRow(const CoxNbr& y) /* This function makes sure that the row for y in d_klList is filled, i.e. that checkKLRow returns true. It does so by actually filling all rows for elements z <= y. */ { allocRowComputation(y); if (ERRNO) return; const SchubertContext& p = schubert(); BitMap b(0); p.extractClosure(b,y); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; if (inverse(z) < z) continue; if (!checkKLRow(z)) { fillKLRow(z); if (ERRNO) return; } if (!checkMuRow(z)) { readMuRow(z); if (ERRNO) return; } if (!checkMuRow(inverse(z))) { inverseMuRow(z); if (ERRNO) return; } } return; } void KLContext::KLHelper::muCorrection(const CoxNbr& y, List& pol) /* This function adds the correction terms corresponding to the mu(x,z) with length difference at least three, for x < z <= ys, and zs > z. The algorithm is as follows : we run through the set of z <= ys with zs > z; for each such z we run through the mu-list of z, which will contain the list of all x < z with odd length-difference > 1 for which mu(x,z) is non-zero, then see if x is in the extremal-list for y, and if yes, do the corresponding addition. */ { const SchubertContext& p = schubert(); BitMap b(0); Generator s = last(y); CoxNbr ys = p.shift(y,s); p.extractClosure(b,ys); b.andnot(p.downset(s)); LFlags fy = p.descent(y); const ExtrRow& e = extrList(y); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; const MuRow& muR = muList(z); for (Ulong j = 0; j < muR.size(); ++j) { CoxNbr x = muR[j].x; LFlags fx = p.descent(x); if ((fx & fy) != fy) // x is not extremal w.r.t. y continue; Ulong k = find(e,x); KLCoeff mu = muR[j].mu; Length h = (p.length(z)-p.length(x)+1)/2; pol[k].add(klPol(z,ys),mu,h); if (ERRNO) { Error(ERRNO,x,y); ERRNO = ERROR_WARNING; return; } } } return; } void KLContext::KLHelper::readMuRow(const CoxNbr& y) /* This function fills the mu-row from the corresponding kl-row. If the row has not been allocated yet, it makes sure that no unnecessary allocations are made. Handles a possible memory error, and returns ERROR_WARNING. */ { const SchubertContext& p = schubert(); const KLRow& kl_row = klList(y); const ExtrRow& e_row = extrList(y); if (!isMuAllocated(y)) { /* make row from scratch */ MuRow mu_buf(0); mu_buf.setSizeValue(0); Length ly = p.length(y); for (Ulong j = 0; j < kl_row.size(); ++j) { CoxNbr x = e_row[j]; Length lx = p.length(x); if ((ly-lx)%2 == 0) continue; if ((ly-lx) == 1) continue; const KLPol& pol = *kl_row[j]; Degree d = (ly-lx-1)/2; if (pol.deg() < d) continue; MuData m(x,pol[d],d); mu_buf.append(m); if (ERRNO) goto abort; } d_kl->d_muList[y] = new MuRow(mu_buf); if (ERRNO) goto abort; status().munodes += mu_buf.size(); status().mucomputed += mu_buf.size(); status().murows++; } else { Ulong i = 0; MuRow& mu_row = muList(y); for (Ulong j = 0; j < muList(y).size(); ++j) { MuData& mu = mu_row[j]; CoxNbr x = mu.x; while(e_row[i] < x) ++i; const KLPol& pol = *kl_row[i]; Length d = mu.height; if (pol.deg() == d) mu.mu = pol[d]; else mu.mu = 0; status().mucomputed++; if (mu.mu == 0) status().muzero++; } } return; abort: Error(ERRNO); ERRNO = MEMORY_WARNING; return; } KLCoeff KLContext::KLHelper::recursiveMu(const CoxNbr& x, const CoxNbr& y, const Generator& s) /* This function computes mu(x,y) using the general recursive formula for the descent s. In practice, this will be used only if the descent set of x contains the _second_ descent set of y. It is assumed that x < y x extremal w.r.t. y, and l(y)-l(x) odd > 1. Sets the error MU_FAIL, and returns the value undef_klcoeff, in case of failure (this can be due to memory overflow, or to coefficient over- or underflow.) */ { const SchubertContext& p = schubert(); Length l = p.length(y) - p.length(x); /* l is odd > 1 */ CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); KLCoeff mu_xy = d_kl->mu(xs,ys); if (ERRNO) goto abort; if (!p.inOrder(x,ys)) { /* value is found */ status().mucomputed++; if (mu_xy == 0) status().muzero++; return mu_xy; } /* add correction terms */ { BitMap b(0); p.extractClosure(b,ys); b.andnot(p.downset(s)); // extract z s.t. zs > z b.andnot(p.parity(x)); // extract elements with opposite length parity // from x BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; if (!p.inOrder(x,z)) continue; if (p.length(z)-p.length(x) == 1) { // x is a coatom of z KLCoeff mu_zys = d_kl->mu(z,ys); if (ERRNO) goto abort; if (mu_zys == 0) continue; safeAdd(mu_xy,mu_zys); if (ERRNO) goto abort; continue; } // if we get here l(z)-l(x) >= 3 KLCoeff a = d_kl->mu(x,z); if (ERRNO) goto abort; if (a == 0) continue; KLCoeff mu_zys = d_kl->mu(z,ys); if (ERRNO) goto abort; if (mu_zys == 0) continue; safeMultiply(a,mu_zys); safeAdd(mu_xy,a); } } /* subtract term from P_{x,ys} */ { const KLPol& pol = klPol(x,ys); Length d = (l-1)/2 - 1; if (pol.deg() == d) { safeSubtract(mu_xy,pol[d]); if (ERRNO) { // overflow; highly unlikely! Error(MU_OVERFLOW,this,x,y); goto abort; } } } return mu_xy; abort: if (ERRNO != MEMORY_WARNING) ERRNO = MU_FAIL; return undef_klcoeff; } void KLContext::KLHelper::writeKLRow(const CoxNbr& y, List& pol) /* This function writes the polynomials from the list pol to klList(y); more precisely, it finds their adresses in klTree(), and writes those to klList(y). First it has to put the true degrees in the pol[j]. It is assumed that y <= inverse(y). The only error that can occur here is memory overflow because of the allocation for new polynomials in klTree(). In that case, the error is treated, and ERROR_WARNING is set. */ { KLRow& kl_row = klList(y); for (Ulong j = 0; j < kl_row.size(); ++j) { if (kl_row[j]) continue; /* find degree of polynomial */ Degree d = pol[j].deg(); for (; d; --d) { if (pol[j][d]) break; } pol[j].setDeg(d); const KLPol* q = klTree().find(pol[j]); if (q == 0) { /* an error occurred */ Error(ERRNO); ERRNO = ERROR_WARNING; return; } kl_row[j] = q; status().klcomputed++; } return; } }; /**************************************************************************** Chapter III -- KLStatus This section defines the functions declared for the KLStatus structure : - KLStatus() : constructor; - ~KLStatus() : destructor; ****************************************************************************/ namespace invkl { KLStatus::KLStatus() :klrows(0), klnodes(0), klcomputed(0), murows(0), munodes(0), mucomputed(0), muzero(0) {} KLStatus::~KLStatus() {} }; /***************************************************************************** Chapter III -- The KLPol class. The KLPol class is derived form Polynomial, because we want to re-define the arithmetic operations so that overflow is carefully checked. This makes them expensive, but arithmetic is only used when the polynomials are defined, and there we have to check anyway. The following functions are defined : - add(p,mu,n) : adds to the current polynomial the product of p and mu, shifted by n; - subtract(p,n) : subtracts p shifted by n from the current polynomial; *****************************************************************************/ namespace invkl { KLPol& KLPol::add(const KLPol& p, const KLCoeff& mu, const Ulong& n) /* Adds the polynomial p*mu.X^n to the current polynomial. We don't test for p = 0 because a k-l polynomial is never zero. Also, we assume that the coefficients are positive, so the degree is easily determined. Also, we assume mu is non-zero. Forwards the error KLCOEFF_OVERFLOW in case of error. */ { if (deg() < p.deg()+n) setDeg(p.deg()+n); for (Ulong j = 0; j <= p.deg(); ++j) { safeAdd(v[j+n],p[j]*mu); if (ERRNO) return *this; } return *this; } KLPol& KLPol::subtract(const KLPol& p, const Ulong& n) /* This function subtracts q^n.p from the current polynomial, checking for underflow. Sets the error KLCOEFF_UNDERFLOW in case of error. */ { /* make sure the degree will hold the computation */ if (deg() < p.deg()+n) setDeg(p.deg()+n); /* subtract */ for (Degree j = 0; j <= p.deg(); ++j) { safeSubtract((*this)[j+n],p[j]); if (ERRNO) return *this; } reduceDeg(); return *this; } }; /**************************************************************************** Chapter IV -- Utility functions This section defines some utility functions used in this module : - one() : returns a constant polynomial equal to one; ****************************************************************************/ namespace { MuData* find(MuRow& row, const CoxNbr& x) /* Finds x in the row and returns the address of the corresponding row. Returns zero if x is not found. Uses binary search. */ { Ulong j0 = (Ulong)(-1); for (Ulong j1 = row.size(); j1-j0 > 1;) { Ulong j = j0 + (j1-j0)/2; if (row[j].x == x) // m was found return row.ptr()+j; if (row[j].x < x) j0 = j; else j1 = j; } return 0; } }; namespace invkl { const KLPol& one() { static KLPol p(1,KLPol::const_tag()); return p; } }; namespace { const KLPol& zeroPol() /* Returns the zero polynomial (usually this indicates an error condition.) */ { static KLPol z(undef_degree); return z; } }; positivity_final/invkl.h0000600000175000017500000001542010011372073017122 0ustar duclouxducloux00000000000000/* This is invkl.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef INVKL_H /* guard against multiple inclusions */ #define INVKL_H #include "globals.h" namespace invkl { using namespace globals; }; /******** type declarations *************************************************/ #include "coxtypes.h" #include "klsupport.h" #include "hecke.h" #include "list.h" #include "polynomials.h" namespace invkl { using namespace coxtypes; using namespace klsupport; using namespace list; using namespace polynomials; }; namespace invkl { class KLContext; class KLPol; struct KLStatus; struct MuData; class MuFilter; typedef List KLRow; typedef List MuRow; typedef List > HeckeElt; }; /******** function declarations *********************************************/ namespace invkl { const KLPol& one(); }; /******** type definitions **************************************************/ #include "bits.h" #include "memory.h" #include "search.h" namespace invkl { using namespace bits; using namespace memory; }; namespace invkl { class KLPol:public Polynomial { public: static PolynomialType polType() {return INV_KLPOL;} KLPol() {}; KLPol(const Ulong& n):Polynomial(n) {}; KLPol(const KLCoeff& c, const_tag):Polynomial(c,const_tag()) {}; ~KLPol() {}; KLPol& add(const KLPol& p, const KLCoeff& mu, const Ulong& n); KLPol& subtract(const KLPol& p, const Ulong& n); }; struct MuData { CoxNbr x; KLCoeff mu; Length height; /* constructors */ MuData() {}; MuData(const CoxNbr& d_x, const KLCoeff& d_mu, const Length& d_h) :x(d_x), mu(d_mu), height(d_h) {}; ~MuData() {}; /* comparison */ bool operator> (const MuData& m) const; /* inlined */ }; struct KLStatus { static const LFlags kl_done = 1L; static const LFlags mu_done = (1L << 1); LFlags flags; Ulong klrows; Ulong klnodes; Ulong klcomputed; Ulong murows; Ulong munodes; Ulong mucomputed; Ulong muzero; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLStatus));} KLStatus(); ~KLStatus(); }; class KLContext { KLSupport* d_klsupport; List d_klList; List d_muList; search::BinaryTree d_klTree; KLStatus* d_status; struct KLHelper; /* provides helper functions */ KLHelper* d_help; friend struct KLHelper; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLContext));} KLContext(KLSupport* kls); ~KLContext(); /* accessors */ const ExtrRow& extrList(const CoxNbr& y) const; /* inlined */ CoxNbr inverse(const CoxNbr& x) const; /* inlined */ const BitMap& involution() const; /* inlined */ bool isExtrAllocated(const CoxNbr& x) const; /* inlined */ bool isFullKL() const; /* inlined */ bool isFullMu() const; /* inlined */ bool isKLAllocated(const CoxNbr& x) const; /* inlined */ bool isMuAllocated(const CoxNbr& x) const; /* inlined */ const KLRow& klList(const CoxNbr& y) const; /* inlined */ const KLSupport& klsupport() const; /* inlined */ Generator last(const CoxNbr& y) const; /* inlined */ const MuRow& muList(const CoxNbr& y) const; /* inlined */ Rank rank() const; /* inlined */ const SchubertContext& schubert() const; /* inlined */ Ulong size() const; /* inlined */ const search::BinaryTree& tree() const; /* inlined */ /* manipulators */ void applyInverse(const CoxNbr& y); void applyIPermutation(const CoxNbr& y, const Permutation& a); /* inlined */ void clearFullKL(); /* inlined */ void clearFullMu(); /* inlined */ void fillKL(); void fillMu(); const KLPol& klPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator); KLCoeff mu(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator); void permute(const Permutation& a); void row(HeckeElt& h, const CoxNbr& y); void revertSize(const Ulong& n); void setFullKL(); /* inlined */ void setFullMu(); /* inlined */ void setSize(const Ulong& n); }; }; /******** inline definitions ************************************************/ namespace invkl { inline bool MuData::operator> (const MuData& m) const {return x > m.x;} inline const ExtrRow& KLContext::extrList(const CoxNbr& y) const {return klsupport().extrList(y);} inline CoxNbr KLContext::inverse(const CoxNbr& x) const {return d_klsupport->inverse(x);} inline const BitMap& KLContext::involution() const {return d_klsupport->involution();} inline bool KLContext::isExtrAllocated(const CoxNbr& x) const {return d_klsupport->isExtrAllocated(x);} inline bool KLContext::isFullKL() const {return d_status->flags&KLStatus::kl_done;} inline bool KLContext::isFullMu() const {return d_status->flags&KLStatus::mu_done;} inline bool KLContext::isKLAllocated(const CoxNbr& x) const {return d_klList[x] != 0;} inline bool KLContext::isMuAllocated(const CoxNbr& x) const {return d_muList[x] != 0;} inline const KLRow& KLContext::klList(const CoxNbr& y) const {return *d_klList[y];} inline const KLSupport& KLContext::klsupport() const {return *d_klsupport;} inline Generator KLContext::last(const CoxNbr& y) const {return d_klsupport->last(y);} inline const MuRow& KLContext::muList(const CoxNbr& y) const {return *d_muList[y];} inline Rank KLContext::rank() const {return d_klsupport->rank();} inline const SchubertContext& KLContext::schubert() const {return d_klsupport->schubert();} inline Ulong KLContext::size() const {return d_klList.size();} inline const search::BinaryTree& KLContext::tree() const {return d_klTree;} inline void KLContext::applyIPermutation(const CoxNbr& y, const Permutation& a) {return rightRangePermute(*d_klList[y],a);} inline void KLContext::clearFullKL() {d_status->flags &= ~KLStatus::kl_done;} inline void KLContext::clearFullMu() {d_status->flags &= ~KLStatus::mu_done;} inline void KLContext::setFullKL() {d_status->flags |= KLStatus::kl_done;} inline void KLContext::setFullMu() {d_status->flags |= KLStatus::mu_done;} }; #endif positivity_final/io.cpp0000600000175000017500000002474210034764035016760 0ustar duclouxducloux00000000000000/* This is io.cpp Coxeter version 3.0_demo Copyright (C) 2001 Fokko du Cloux See file main.cpp for full copyright notice */ #include #include #include "io.h" /**************************************************************************** This file used to be one of the biggest in the program; now it contains just some elementary output functions that really pertain to the standard libraries; in the current stage of the transition, and also because of nagging worries about memory allocation performance, I have preferred to keep my own clumsy string types. The interaction with the user has been farmed out to interactive.c; the output functions for the Coxeter group have gone mostly to interface.c; and the output functions for the various types are in the corresponding files (with the exception of polynomials, because I got stuck in the template problems.) ****************************************************************************/ /***************************************************************************** Chapter I -- The String class *****************************************************************************/ namespace io { String::~String() /* Simply destroy the underlying List. */ {} }; /***************************************************************************** Chapter I --- Output functions returning strings This section regroups various output functions returning strings. We have not strived for speed, but for safety and robustness. The main aim has been to procure output functions that are easy to use, and relieve the user from the worries of having to allocate memory, or watch out for overflow. So usually each function posesses its own "safe" place, and the result is returned as a pointer to there. The size of the safe area is grown as necessary. The functions provided here are : - append(l,c) : appends the character c to the varstring l; - append(l,s) : appends the (c)string s to the varstring l; - append(l1,l2) : appends the varstring l2 to the varstring l1; - append(l,n) : appends the Ulong (int) n to the varstring l; - erase(l,n) : erases the last n characters from l; - pad(l,n) : pads l with spaces to length n; - reset(l) : resets a varstring to the empty line; - setString(l,s,first,r) : sets l to a substring of s; ******************************************************************************/ namespace io { String& append(String& l, const char c) /* Appends c to the varstring l, resizing l as necessary. */ { l[l.length()] = c; l.setLength(l.length()+1); l[l.length()] = 0; return l; } String& append(String& l, const char *s) /* Appends s to the varstring l, resizing l as necessary. */ { l.setLength(l.length()+strlen(s)); strcat(l.ptr(),s); return l; } String& append(String& l1, const String& l2) /* Appends l2 to the varstring l1, resizing l1 as necessary. */ { l1.setLength(l1.length()+l2.length()); strcat(l1.ptr(),l2.ptr()); return l1; } String& append(String& str, const Ulong& n) { static String cs(digits(ULONG_MAX,10)); cs.setLength(sprintf(cs.ptr(),"%lu",n)); append(str,cs); return str; } String& append(String& str, const long& m) { static String cs(digits(LONG_MAX,10)+1); cs.setLength(sprintf(cs.ptr(),"%ld",m)); append(str,cs); return str; } String& append(String& l, const int *v, const Ulong& n) /* Appends to l the string representation of the n first elements pointed by v, as a comma-separated and square-bracket-enclosed list. */ { static String buf(0); reset(buf); append(buf,"["); for (Ulong j = 0; j < n; j++) { append(buf,v[j]); if (j+1 < n) /* more to come */ append(buf,","); } append(buf,"]"); return l; } String& append(String& str, const unsigned& n) { static String cs(digits(UINT_MAX,10)+1); cs.setLength(sprintf(cs.ptr(),"%u",n)); append(str,cs); return str; } String& append(String& str, const int& n) { static String cs(digits(INT_MAX,10)+1); cs.setLength(sprintf(cs.ptr(),"%d",n)); append(str,cs); return str; } String& erase(String&l, const Ulong& n) /* Erases the last n letters from the string l (everything if n >= length) */ { if (n >= l.length()) /* erase everything */ return reset(l); l[l.length()-n] = '\0'; l.setLength(l.length()-n); return l; } String& pad(String& l, const Ulong& n) /* Pads the string with white spaces to length n. NOTE : zero-termination is automatic because we get clean memory on resize. */ { if (n <= l.length()) /* do nothing */ return l; int a = l.length(); l.setLength(n); sprintf(l.ptr()+a,"%*s",static_cast(n-a),""); return l; } String& reset(String& l) /* Resets l to the empty string. */ { l[0] = '\0'; l.setLength(0); return l; } String& setString(String& l, const String& s, const Ulong& first, const Ulong& r) /* Sets the string l to the subword of s starting at first, with length r. */ { l.setLength(r); l.setData(s.ptr()+first,0,r); l[r] = '\0'; return l; } const String& String::undefined() /* This function returns an impossible string, namely the one corresponding to a list of zero characters. Its length would be -1. */ { static String str; /* uses private default constructor */ return str; } }; /***************************************************************************** Chapter II --- Output to files This chapter regroups some basic input/output functions at the level of strings and such. Of course this should have come from the STL. The following functions are provided : - foldLine(file,str,ls,h,hyphens) : fold a long output line into file; - print(file,str) : prints the (var)string to the file; - print(file,v,n) : prints a list of integers; - printFile(file,name) : prints the contents of the file name; - printFile(file,name,dir_name) : prints the contents of the file dir_name/name; ******************************************************************************/ namespace io { void foldLine(FILE* file, const String& str, const Ulong& ls, const Ulong& h, const char* hyphens) /* This function breaks up the string str into lines of at most ls characters to improve output of long lines. It outputs the extra lines with an indentation of h white spaces. It chooses a breakpoint just before one of the characters in the string hyphens, whenever possible; otherwise it breaks the line brutally. */ { String buf(0); if (str.length() <= ls) { /* str fits on one line */ print(file,str); return; } /* search for hyphenation point */ Ulong bp = 0; for (Ulong j = 0; j < ls; j += strcspn(str.ptr()+j,hyphens)) { bp = j; j++; } if (bp == 0) /* break brutally */ bp = ls; setString(buf,str,0,bp); print(file,buf); /* print continuation lines */ Ulong p = bp; for (; p < str.length()-ls+h; p += bp) { bp = 0; for (Ulong j = 0; j < ls-h; j += strcspn(str.ptr()+p+j,hyphens)) { bp = j; j++; } if (bp == 0) bp = ls-h; setString(buf,str,p,bp); fprintf(file,"\n%*s",static_cast(h),""); print(file,buf); } /* print last line */ setString(buf,str,p,str.length()-p); fprintf(file,"\n%*s",static_cast(h),""); print(file,buf); return; } void print(FILE *file, const int* const& v, const Ulong& n) /* Appends to l the string representation of the n first elements pointed by v, as a comma-separated and square-bracket-enclosed list. */ { fprintf(file,"["); for (Ulong j = 0; j < n; j++) { fprintf(file,"%d",v[j]); if (j+1 < n) /* more to come */ fprintf(file,","); } fprintf(file,"]"); return; } void printFile(FILE* file, const char *name, const char *dir_name) /* Prints the contents of the file with the name dir_name/name on the file. */ { static String buf(0); reset(buf); append(buf,dir_name); append(buf,"/"); append(buf,name); FILE* inputfile; char c; inputfile = fopen(buf.ptr(),"r"); if (inputfile == 0) { Error(FILE_NOT_FOUND,buf.ptr()); return; } while((c = getc(inputfile)) != EOF) putc(c,file); fclose(inputfile); return; } void printFile(FILE* file, const char *name) /* Prints the contents of the file with the given name, onto file. */ { FILE* inputfile; char c; inputfile = fopen(name,"r"); if (inputfile == 0) { Error(FILE_NOT_FOUND,name); return; } while((c = getc(inputfile)) != EOF) putc(c,file); fclose(inputfile); return; } }; /***************************************************************************** Chapter III -- General input functions. This section contains general input functions. The following functions are defined : - getInput(file,buf) : the universal input function; ******************************************************************************/ namespace io { char* getInput(FILE *inputfile, String& buf, Ulong len) /* Reads from the inputfile until either EOF or a newline is reached; appends the result to buf starting from position len; resizes buf as it reads, so that it can keep writing. The newline is not written on the string. */ { for (Ulong a = len;; a++) { int c = getc(inputfile); buf.setLength(a); if ((c == EOF) || (c == '\n')) { buf[a] = '\0'; break; } buf[a] = c; } return buf.ptr(); } }; /***************************************************************************** Chapter III --- Miscellaneous. This chapter regroups various functions that did not seem to fall into any of the other categories : - alphabeticDigits(c,b) : returns the number of digits in alphabetic representation ******************************************************************************/ namespace io { int alphabeticDigits(Ulong c, Ulong b) /* Returns the number of digits for the alphabetic representation of c with b letters. In this representation, the numbers n s.t. 1 + b + ... + b^(d-1) <= n < 1 + b + ... + b^d are representable with d digits (and 0 is represented by the empty word.) */ { Ulong j = 0; for(; c; c = (c-1)/b) ++j; return j; } int digits(Ulong c, Ulong b) /* Returns the number of digits in the representation of c in base b. */ { int j = 1; for (c /= b; c; c /= b) ++j; return j; } Ulong skipSpaces(const String& l, Ulong p) /* Skips from character position p over white space (characters recognized by isspace()) */ { Ulong j = 0; for (; isspace(l[p+j]); ++j) ; return j; } }; positivity_final/iterator.h0000600000175000017500000000303410011171251017621 0ustar duclouxducloux00000000000000/* This is iterator.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef ITERATOR_H /* guard against multiple inclusions */ #define ITERATOR_H #include "globals.h" namespace iterator { using namespace globals; }; /******** type declarations **************************************************/ namespace iterator { template class FilteredIterator; template class ComposedIterator; }; /******** type definitions ***************************************************/ /* FilteredIterator is an iterator adapter. The idea is that I is an iterator class, F a functor class. Objects of type f take one argument of the value-type of I, and return a boolean. The new iterator traverses the values of the old one for which the function object returns true. T is the value-type of I. */ namespace iterator { template class FilteredIterator { private: I d_i; I d_max; const F& d_f; public: FilteredIterator(I i, I max, const F& f):d_i(i),d_max(max),d_f(f) { for (; d_i != d_max; ++d_i) { if (d_f(*d_i)) break; } } ~FilteredIterator() {}; T operator* () {return *d_i;} FilteredIterator& operator++ () { for (++d_i; d_i != d_max; ++d_i) { if (d_f(*d_i)) break; } return *this; } bool operator== (const FilteredIterator& i) const {return d_i == i.d_i;} bool operator!= (const FilteredIterator& i) const {return d_i != i.d_i;} }; }; #endif positivity_final/kl.cpp0000600000175000017500000023675710012720012016751 0ustar duclouxducloux00000000000000/* This is kl.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "kl.h" #include "error.h" #include "iterator.h" namespace kl { using namespace error; using namespace iterator; } /**************************************************************************** This file contains the code for the computation of the (ordinary) Kazhdan- Lusztig polynomials for W. The kl context maintains two main lists : klList and muList. Each of these has one pointer (to a KLRow and a MuRow, respectively) for each element in the current schubert context; the enlargement and permutation functions for the schubert context make sure that the various active k-l contexts are enlarged/permuted accordingly. The row y in klList, when allocated, contains one entry for each extremal x <= y; the list of those x can be gotten from the klsupport structure, which maintains these extremal lists. The lists of extremal pairs are shared among all k-l contexts. Each entry in klList(y) is simply a pointer to a (constant) polynomial, the k-l polynomial for (x,y). The main complication is that I've (rightly or wrongly) decided to not allocate klList(y) if inverse(y) < y; in that case, the polynomial is read from the list for inverse(y). This saves space, but makes lookup more complicated. More importantly though, the fact of systematically going over to inverse(y) when it is smaller, seems to make the algorithm quite a bit faster and leaner (in the sense that fewer rows need to be computed); this, more than the memory saving, is my main reason for keeping this complication in. The situation for mu-rows is a little bit more delicate. First of all, we do not here go over to inverses; we fill all the rows that are needed (using the mu-value for the inverses if it is available.) Further, we only look at pairs where the length difference is at least three; it is known that we can then reduce to extremal pairs, the other mu-values being zero. But in fact, even among extremal pairs, most values are zero as well. So we do not necessarily allocate one entry for each pair; what is guaranteed is that all entries correspond to extremal pairs, and all non-zero mu-values have an entry. Ideally, we would wish to allocate only the non-zero mu's; however, this would require computing a full row as soon as one coefficient is needed, so we have refrained from that. Anyway, to find out the value for mu(x,y), we extremalize x, check that the length difference is odd >= 3, look x up in muList(y), and return the corresponding mu-value if found, 0 otherwise. The idea is to compute everything upon request : we compute exactly what is needed in the recursive computation of what is required. The requests that we mainly focus on are the following : - compute a single k-l polynomial (mu-coefficient); - compute all P_{x,y}'s (mu(x,y)'s) for a given y; - compute the full file of k-l polynomials (mu coefficients); It turns out that the dominant factor in the computation is the Bruhat order comparison. That is why computing a whole row can be done much more efficently than computing each entry in the row separately : using our closure function from the schubert context, we can basically factor out most of the Bruhat things for a whole row. In any case, the row computation can be done without a single call to the slow inOrder function! ****************************************************************************/ namespace kl { struct KLContext::KLHelper { /* data */ KLContext* d_kl; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLHelper));} KLHelper(KLContext* kl):d_kl(kl) {}; ~KLHelper() {}; /* member functions */ void allocExtrRow(const CoxNbr& y) {klsupport().allocExtrRow(y);} void allocKLRow(const CoxNbr& y); void allocMuRow(const CoxNbr& y); void allocMuRow(MuRow& row, const CoxNbr& y); void allocMuTable(); void allocRowComputation(const CoxNbr& y); bool checkKLRow(const CoxNbr& y); bool checkMuRow(const CoxNbr& y); void coatomCorrection(const CoxNbr& y, List& pol); void coatomCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, List& pol, const Ulong& a); KLCoeff computeMu(const CoxNbr& x, const CoxNbr& y); const ExtrRow& extrList(const CoxNbr& y) {return klsupport().extrList(y);} void fillMuRow(MuRow& row, const CoxNbr& y); const KLPol* fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator); void fillKLRow(const CoxNbr& y); void initWorkspace(const CoxNbr& y, List& pol); CoxNbr inverse(const CoxNbr& y) {return klsupport().inverse(y);} void inverseMuRow(const CoxNbr& y); bool isExtrAllocated(const CoxNbr& y) {return klsupport().isExtrAllocated(y);} bool isKLAllocated(const CoxNbr& y) {return d_kl->isKLAllocated(y);} bool isMuAllocated(const CoxNbr& y) {return d_kl->isMuAllocated(y);} KLRow& klList(const CoxNbr& y) {return *d_kl->d_klList[y];} const KLPol& klPol(const CoxNbr& x, const CoxNbr& y) {return d_kl->klPol(x,y);} KLSupport& klsupport() {return d_kl->d_klsupport[0];} BinaryTree& klTree() {return d_kl->d_klTree;} Generator last(const CoxNbr& x) {return klsupport().last(x);} void makeMuRow(const CoxNbr& y); KLCoeff mu(const CoxNbr& x, const CoxNbr& y) {return d_kl->mu(x,y);} void muCorrection(const CoxNbr& y, List& pol); void muCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, List& pol, const Ulong& a); MuRow& muList(const CoxNbr& y) {return *d_kl->d_muList[y];} void prepareRow(const CoxNbr& y, const Generator& s); Rank rank() {return d_kl->rank();} void readMuRow(const CoxNbr& y); KLCoeff recursiveMu(const CoxNbr& x, const CoxNbr& y, const Generator& s); const SchubertContext& schubert() {return klsupport().schubert();} void secondTerm(const CoxNbr& y, List& pol); Ulong size() {return d_kl->size();} KLStatus& status() {return *d_kl->d_status;} void writeKLRow(const CoxNbr& y, List& pol); void writeMuRow(const MuRow& row, const CoxNbr& y); }; }; namespace { using namespace kl; struct PolPtrF { typedef const KLPol* valueType; const KLPol* operator()(const KLPol* pol) {return pol;} }; void allocExtrRow(KLContext& kl, ExtrRow& row, const CoxNbr& y); void appendStar(String& str, const KLContext& kl, const CoxNbr& x, const KLPol& pol, const Length& l); MuData* find(MuRow& row, const CoxNbr& x); void printStar(FILE* file, const KLContext& kl, const CoxNbr& x, const KLPol& pol, const Length& l); KLPol& safeAdd(KLPol& p, const KLPol& q, const Degree& n); KLPol& safeSubtract(KLPol& p, const KLPol& q, const KLCoeff& mu, const Length& h); void showSimpleMu(FILE* file, KLContext& kl, const CoxNbr& x, const CoxNbr& y, const KLCoeff& r, const Interface& I); void showRecursiveMu(FILE* file, KLContext& kl, const CoxNbr& x, const CoxNbr& y, const KLCoeff& r, const Interface& I); KLPol& zeroPol(); }; /**************************************************************************** Chapter I --- The KLContext class This section defines the functions for the KLContext class. The following functions are defined : constructors and destructors : - KLContext(KLSupport* kls); - ~KLContext(); accessors : manipulators : - applyInverse(y) : exchanges rows in klList for y and y_inverse; - fillKL() : fills the full k-l table; - fillMu() : fills the full mu-table; - klPol(x,y) : for x <= y, returns the Kazhdan-Lusztig polynomial; - klPol(x,y,s) : same as above, using s as descent; - lcell() : returns the left cell partition; - lrcell() : returns the two-sided cell partition; - mu(x,y) : for x <= y, returns the mu-coefficient; - rcell() : returns the right cell partition; - row(h,y,I) : returns the row of the CoxNbr y in h; - row(e_row,kl_row,y) : returns the row of the CoxNbr y; - revertSize(n) : reverts the size to size n; - setSize(n) : extends the context to size n; input/output : - printStatus(file) : prints the status; ****************************************************************************/ namespace kl { KLContext::KLContext(KLSupport* kls) :d_klsupport(kls), d_klList(kls->size()), d_muList(kls->size()) { d_status = new KLStatus; d_help = new KLHelper(this); d_klList.setSizeValue(kls->size()); d_klList[0] = new KLRow(1); d_klList[0]->setSizeValue(1); d_klList[0][0][0] = d_klTree.find(one()); d_status->klnodes++; d_status->klrows++; d_status->klcomputed++; d_muList.setSizeValue(kls->size()); d_muList[0] = new MuRow(0); } KLContext::~KLContext() /* Recall that a KLContext is assumed to own its SchubertContext. The only destructions that are not done automatically are those of the Schubert context, the status pointer, and the extrList pointers. */ { for (Ulong j = 0; j < size(); ++j) { delete d_klList[j]; delete d_muList[j]; } delete d_status; return; } /******** manipulators *******************************************************/ void KLContext::applyInverse(const CoxNbr& x) /* Exchanges rows for x and x_inverse in klList. It is assumed that the row for x_inverse is allocated. */ { CoxNbr xi = inverse(x); d_klList[x] = d_klList[xi]; d_klList[xi] = 0; } void KLContext::fillKL() /* This function fills all the rows in klList, in a straightforward way. */ { if (isFullKL()) return; for (CoxNbr y = 0; y < size(); ++y) { if (inverse(y) < y) continue; if (!isKLAllocated(y)) d_help->allocKLRow(y); d_help->fillKLRow(y); d_help->readMuRow(y); } setFullKL(); return; } void KLContext::fillMu() /* This function fills all the rows in the mu-list, in a straightforward way. Sets the error ERROR_WARNING in case of error. NOTE : error handling should be improved! */ { if (isFullMu()) return; static MuRow mu_row(0); d_help->allocMuTable(); if (ERRNO) goto abort; for (CoxNbr y = 0; y < size(); ++y) { if (inverse(y) < y) d_help->inverseMuRow(inverse(y)); d_help->fillMuRow(*d_muList[y],y); if (ERRNO) goto abort; } setFullMu(); return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } const KLPol& KLContext::klPol(const CoxNbr& d_x, const CoxNbr& d_y, const Generator& s) /* This function returns the Kazhdan-Lusztig polynomial P_{x,y}. It is assumed that the condition x <= y has already been checked, and that x and y are valid context numbers. */ { CoxNbr x = d_x; CoxNbr y = d_y; const SchubertContext& p = schubert(); /* put x in extremal position w.r.t. y */ x = p.maximize(x,p.descent(y)); /* check for trivial cases */ if (p.length(y) - p.length(x) < 3) { /* result is 1 */ return one(); } /* go to inverses if necessary */ if (inverse(y) < y) { y = inverse(y); x = inverse(x); } /* check if extrList[y] is allocated */ if (!isKLAllocated(y)) { d_help->allocKLRow(y); if (ERRNO) return zeroPol(); } /* find x in extrList[y] */ Ulong m = find(extrList(y),x); const KLPol*& pol = d_help->klList(y)[m]; if (pol == 0) { /* we have to compute the polynomial */ pol = d_help->fillKLPol(x,y,s); if (ERRNO) return zeroPol(); } return *pol; } KLCoeff KLContext::mu(const CoxNbr& x, const CoxNbr& y) /* This function returns the mu-coefficient mu(x,y). It is assumed that the condition x <= y has already been checked, and that x and y are valid context numbers. The return value is zero if the length difference is even. If an error occurs, it forwards the error value and returns the value undef_klcoeff for mu. */ { const SchubertContext& p = schubert(); Length d = p.length(y) - p.length(x); if (d%2 == 0) return 0; if (d == 1) /* x is a coatom of y */ return 1; /* check if x is in extremal position w.r.t. y */ if (x != p.maximize(x,p.descent(y))) return 0; /* allocate *d_muList[y] if necessary */ if (!isMuAllocated(y)) { d_help->allocMuRow(y); if (ERRNO) return undef_klcoeff; } /* find x in *d_muList[y] */ MuRow& m = *d_muList[y]; MuData* md = find(m,x); if (md == 0) return 0; if (md->mu == undef_klcoeff) { /* we need to compute the coefficient */ md->mu = d_help->computeMu(x,y); if (ERRNO) return undef_klcoeff; } return md->mu; } void KLContext::permute(const Permutation& a) /* This function permutes the context according to the permutation a. The following objects have to be permuted : - klList, muList : each row is a table with values in the context; the list itself has range in the context; don't forget to sort the permuted rows! - inverse : range and values in the context, with some annoyance caused by undef_coxnbr values; - last : range in the context; Applying a permutation to something goes as follows. The permutation a is the table of the function which assigns to each x in the context its number in the new enumeration. Applying this to the context means the following : (a) for tables with _values_ in the context, we need to replace t[j] with a[t[j]]; (b) for tables with _range_ in the context, we need to put t[x] at a[x]; this amounts to replacing t[x] by t[a_inv[x]] for all x; (c) for tables with both range and values in the context, we need to do both : replace t[x] with a[t[a_inv[x]]]; in practice this is done by first replacing the values as in (a), then permuting as in (b). The replacements in (a) are straightforward. The permutations in (b) are more delicate, and would seem to require additional memory for each list to be transformed. In fact, things can be done in place. The thing is to use the cycle decomposition of the permutation : put t[x] at position a[x], t[a[x]] at position a^2[x], ... t[a^{k-1}[x]] at position x, if a^k[x] = x. This requires only the use of the bitmap of a to mark off the entries that have been handled, and skip to the next entry. */ { /* permute values */ for (CoxNbr y = 0; y < size(); ++y) { if (!isMuAllocated(y)) continue; MuRow& row = *d_muList[y]; for (Ulong j = 0; j < row.size(); ++j) row[j].x = a[row[j].x]; row.sort(); } /* permute ranges */ BitMap b(a.size()); for (CoxNbr x = 0; x < size(); ++x) { if (b.getBit(x)) continue; if (a[x] == x) { b.setBit(x); continue; } for (CoxNbr y = a[x]; y != x; y = a[y]) { /* back up values for y */ KLRow* kl_buf = d_klList[y]; MuRow* mu_buf = d_muList[y]; /* put values for x in y */ d_klList[y] = d_klList[x]; d_muList[y] = d_muList[x]; /* store backup values in x */ d_klList[x] = kl_buf; d_muList[x] = mu_buf; /* set bit*/ b.setBit(y); } b.setBit(x); } return; } void KLContext::revertSize(const Ulong& n) /* Reverts the sizes of the lists to size n. This is meant to be used only immediately after a failing context extension, to preserve the consistency of the various list sizes. In particular, it will fail miserably if a premutation has taken place in-between. */ { d_klList.setSize(n); d_muList.setSize(n); return; } void KLContext::row(HeckeElt& h, const CoxNbr& y) /* This function returns in h the data for the full row of y in the k-l table, sorted in the context number order. */ { if (!d_help->checkKLRow(y)) { d_help->allocRowComputation(y); d_help->fillKLRow(y); } if (ERRNO) { Error(ERRNO); ERRNO = ERROR_WARNING; return; } if (y <= inverse(y)) { const ExtrRow& e = extrList(y); h.setSize(e.size()); const KLRow& klr = klList(y); for (Ulong j = 0; j < e.size(); ++j) { h[j].setData(e[j],klr[j]); } } else { /* go over to inverses */ CoxNbr yi = inverse(y); const ExtrRow& e = extrList(yi); h.setSize(e.size()); const KLRow& klr = klList(yi); for (Ulong j = 0; j < e.size(); ++j) { h[j].setData(inverse(e[j]),klr[j]); } h.sort(); /* make sure list is ordered */ } return; } void KLContext::setSize(const Ulong& n) /* This function extends the context so that it can accomodate n elements. The idea is to have the same size as the basic schubert context. */ { CoxNbr prev_size = size(); CATCH_MEMORY_OVERFLOW = true; d_klList.setSize(n); if (ERRNO) goto revert; d_muList.setSize(n); if (ERRNO) goto revert; CATCH_MEMORY_OVERFLOW = false; clearFullKL(); clearFullMu(); return; revert: CATCH_MEMORY_OVERFLOW = false; revertSize(prev_size); return; } /******** input/output ******************************************************/ void KLContext::printStatus(FILE* file) const /* This function prints the status of the context. This is a data structure that monitors precisely the computations that have been effected, and the memory that has been allocated. */ { fprintf(file,"klrows = %lu\n",d_status->klrows); fprintf(file,"klnodes = %lu\n",d_status->klnodes); fprintf(file,"klcomputed = %lu\n",d_status->klcomputed); fprintf(file,"murows = %lu\n",d_status->murows); fprintf(file,"munodes = %lu\n",d_status->munodes); fprintf(file,"mucomputed = %lu\n",d_status->mucomputed); fprintf(file,"muzero = %lu\n",d_status->muzero); return; } /******** to be taken out! **************************************************/ void KLContext::compareMu() /* This function compares the mu-values gotten directly from the k-l polynomials to those from fillMu. */ { static MuRow mu_row(0); fillMu(); printStatus(stdout); for (CoxNbr y = 0; y < size(); ++y) { if (inverse(y) < y) continue; if (!isKLAllocated(y)) d_help->allocKLRow(y); d_help->fillKLRow(y); const MuRow& mu_row = muList(y); const ExtrRow& e = extrList(y); const KLRow& kl_row = klList(y); Ulong i = 0; for (Ulong j = 0; j < mu_row.size(); ++j) { CoxNbr x = mu_row[j].x; while(e[i] < x) ++i; const KLPol& pol = *kl_row[i]; Length d = mu_row[j].height; if (pol.deg() == d) { if (mu_row[j].mu != pol[d]) printf("error! x = %lu, y = %lu\n",static_cast(x), static_cast(y)); } else { if(mu_row[j].mu != 0) printf("error! x = %lu, y = %lu\n",static_cast(x), static_cast(y)); } } } } }; /**************************************************************************** Chapter II -- The KLHelper class The purpose of the KLHelper class is to hide from the public eye a number of helper functions, used in the construction and maintenance of the k-l context. This unclutters kl.h quite a bit. The following functions are defined : - allocExtrRow(const CoxNbr& y) : allocates a row in the extremal list; - allocKLRow(const CoxNbr& y) : allocates a row in the k-l list; - allocMuRow(const CoxNbr& y) : allocates a row in the mu list; - allocMuRow(MuRow& row, const CoxNbr& y) : same, for an external mu-row; - allocMuTable() : allocates the full mu-table; - allocRowComputation(const CoxNbr& y) : initial allocation for a row-computation - checkKLRow(const CoxNbr& y) : checks if a k-l row is fully computed; - coatomCorrection(const CoxNbr& y, List& pol) : subtracts the terms ofr coatoms in the mu-correction, for a full row; - coatomCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, List& pol, const Ulong& a) : same, for a single polynomial - computeMu(const CoxNbr& x, const CoxNbr& y) : computes a mu-coefficient; - fillMuRow(MuRow& row, const CoxNbr& y) : fills a row in the mu-table; - fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator) : fills in one polynomial, using s as descent; - fillKLRow(const CoxNbr& y) : fills in one row in the k-l table; CoxNbr inverse(const CoxNbr& y) : returns the inverse of y; - initWorkspace(const CoxNbr& y, List& pol) : another preliminary to the computation of a row; - inverseMuRow(const CoxNbr& y) : constructs the mu-row for y from that of the inverse of y; - makeMuRow(const CoxNbr& y); - muCorrection(const CoxNbr& y, List& pol) : subtracts the non-coatom mu-part in the computation of a row; - muCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, List& pol, const Ulong& a) : subtracts the non-coatom mu-part, for the computation of a single polynomial; - muList(const CoxNbr& y) : returns the row for y in muList; - prepareRow(const CoxNbr& y, const Generator& s) : a preliminary to the computation of a row; - readMuRow(const CoxNbr& y) : fills in the mu-row from the k-l row; - recursiveMu(const CoxNbr& x, const CoxNbr& y, const Generator& s) : computes mu(x,y) using the general recursive formula; - secondTerm(const CoxNbr& y, List& pol) : takes care of the second term P_{x,ys} in the computation of a full row; - writeKLRow(const CoxNbr& y, List& pol) : transfers the polynomials from pol to klList; - writeMuRow(const MuRow& row, const CoxNbr& y) transfers the mu-coefficients from row to muList; ****************************************************************************/ namespace kl { void KLContext::KLHelper::allocKLRow(const CoxNbr& y) /* This function allocates one row of the kl_list. The row contains one entry for each x <= y which is extremal w.r.t. the descent set of y. The algorithm is as follows : we extract the interval [e,y] as a bitmap, extremalize it by intersecting with the downsets for the various generators, and read it into the row. Forwards the error MEMORY_WARNING if there is a memory overflow and CATCH_MEMORY_OVERFLOW is turned on. */ { if (!isExtrAllocated(y)) allocExtrRow(y); Ulong n = extrList(y).size(); d_kl->d_klList[y] = new KLRow(n); if (ERRNO) return; klList(y).setSizeValue(n); status().klnodes += n; status().klrows++; return; } void KLContext::KLHelper::allocMuRow(const CoxNbr& y) /* This function allocates one row in the muList. There is one entry for each x < y which is extremal w.r.t. y, and has odd length-difference > 1 with y. As with allocKLRow, this function is not designed for maximal efficiency; row allocations for big computations should be handled differently. */ { typedef FilteredIterator EI; typedef FilteredIterator BI; const SchubertContext& p = schubert(); ExtrRow e(0); MuFilter f(p,y); if (isExtrAllocated(y)) { EI first(extrList(y).begin(),extrList(y).end(),f); EI last(extrList(y).end(),extrList(y).end(),f); new(&e) ExtrRow(first,last); } else { BitMap b(size()); p.extractClosure(b,y); if (ERRNO) return; maximize(p,b,p.descent(y)); BI first(b.begin(),b.end(),f); BI last(b.end(),b.end(),f); new(&e) ExtrRow(first,last); } Length ly = p.length(y); d_kl->d_muList[y] = new MuRow(e.size()); if (ERRNO) goto abort; muList(y).setSizeValue(e.size()); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr x = e[j]; Length lx = p.length(x); new(muList(y).ptr()+j) MuData(x,undef_klcoeff,(ly-lx-1)/2); } status().munodes += e.size(); status().murows++; return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::allocMuRow(MuRow& row, const CoxNbr& y) /* Like allocMuRow(const CoxNbr& y), but does the allocation in row. NOTE : this function does not worry about memory overflow. This should probably be revised. */ { const SchubertContext& p = schubert(); ExtrRow e(0); if (isExtrAllocated(y)) { /* extremal row is already available */ e = extrList(y); } else { /* make it from scratch */ BitMap b(size()); p.extractClosure(b,y); maximize(p,b,p.descent(y)); readBitMap(e,b); } /* extract elements with odd length difference > 1 */ Ulong mu_count = 0; Length ly = p.length(y); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr x = e[j]; Length lx = p.length(x); if ((ly-lx)%2 == 0) continue; if (ly-lx == 1) continue; e[mu_count] = x; mu_count++; } row.setSize(mu_count); for (Ulong j = 0; j < mu_count; ++j) { CoxNbr x = e[j]; Length lx = p.length(x); new(row.ptr()+j) MuData(x,undef_klcoeff,(ly-lx-1)/2); } return; } void KLContext::KLHelper::allocMuTable() /* This function does the allocation of the full muList, using the closure iterator. It is not as satisfactory as it should be, because the rows are not obtained in order, and therefore we can not fill them right away to eliminate zero entries. So I am currently not too happy with the situation. Even if we recover the memory later on, it will be highly fragmented. So currently this is just an exercise in formal elegance. */ { typedef FilteredIterator I; const SchubertContext& p = schubert(); for (ClosureIterator cl(p); cl; ++cl) { CoxNbr y = cl.current(); if (inverse(y) < y) continue; if (isMuAllocated(y)) continue; /* find extremal list */ BitMap b = cl().bitMap(); if (ERRNO) { printf("error! y = %lu\n",static_cast(y)); goto abort; } maximize(p,b,p.descent(y)); MuFilter f(p,y); I first(b.begin(),b.end(),f); I last(b.end(),b.end(),f); ExtrRow e(first,last); if (ERRNO) { goto abort; } /* transfer to muList */ Length ly = p.length(y); d_kl->d_muList[y] = new MuRow(e.size()); muList(y).setSizeValue(e.size()); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr x = e[j]; Length lx = p.length(x); MuData mu_data(x,undef_klcoeff,(ly-lx-1)/2); muList(y).append(mu_data); if (ERRNO) { goto abort; } } status().murows++; status().munodes += e.size(); } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::allocRowComputation(const CoxNbr& y) /* This function does the primary memory allocation for the computation of a schubert row. This means that for each initial subword of the normal form of y, we check if the corresponding row in klList (or the inverse row, if appropriate) is allocated, and if not, do the allocation. First, we determine the sequence of left and right shifts that takes y to the identity element, as follows : if inverse(y) >= y, we shift on the right by last(y); else, we shift on the left by last(inverse(y)), and get the inverse of the element which will be used for the recursion for inverse(y). So when we reconstruct the interval using this sequence of shifts, we know that when we apply a left shift we are actually constructing the inverse of the interval we want. We can do this in one pass, as we extract the interval [e,y]. Deals with the possible memory error, and returns ERROR_WARNING in case of error. */ { klsupport().allocRowComputation(y); List g(0); klsupport().standardPath(g,y); CoxNbr y1 = 0; for (Ulong j = 0; j < g.size(); ++j) { Generator s = g[j]; y1 = schubert().shift(y1,s); CoxNbr y2 = klsupport().inverseMin(y1); const ExtrRow& e = extrList(y2); if (!isKLAllocated(y2)) { d_kl->d_klList[y2] = new KLRow(e.size()); if (ERRNO) goto abort; klList(y2).setSizeValue(extrList(y2).size()); status().klnodes += extrList(y2).size(); status().klrows++; } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } bool KLContext::KLHelper::checkKLRow(const CoxNbr& d_y) /* This function checks if the row for y (or for inverse(y) if appropriate) in klList has been filled. */ { CoxNbr y = d_y; if (inverse(y) < y) y = inverse(y); if (!isKLAllocated(y)) /* row is not allocated */ return false; KLRow& kl_row = klList(y); for (Ulong j = 0; j < kl_row.size(); ++j) { if (kl_row[j] == 0) return false; } return true; } bool KLContext::KLHelper::checkMuRow(const CoxNbr& y) /* This function checks if the row for y in muList has been filled. */ { if (!isMuAllocated(y)) /* row is not allocated */ return false; const MuRow& mu_row = muList(y); for (Ulong j = 0; j < mu_row.size(); ++j) { if (mu_row[j].mu == undef_klcoeff) return false; } return true; } void KLContext::KLHelper::coatomCorrection(const CoxNbr& y, List& pol) /* This function subtracts the coatom correction from the list of polynomials. For each coatom z of ys, this is done for all the relevant x-es, as in muCorrection. */ { const SchubertContext& p = schubert(); BitMap b(size()); const ExtrRow& e = extrList(y); Generator s = last(y); CoxNbr ys = p.rshift(y,s); const CoatomList& c = p.hasse(ys); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr z = c[j]; if (p.shift(z,s) > z) continue; p.extractClosure(b,z); maximize(p,b,p.descent(y)); Ulong i = 0; BitMap::Iterator b_end = b.end(); for (BitMap::Iterator k = b.begin(); k != b_end; ++k) { CoxNbr x = *k; while (e[i] < x) ++i; safeSubtract(pol[i],klPol(x,z),1,1); if (ERRNO) { Error(ERRNO,this,x,y); ERRNO = ERROR_WARNING; return; } } } return; } void KLContext::KLHelper::coatomCorrection(const CoxNbr& x, const CoxNbr& y, const Generator& s, List& pol, const Ulong& a) /* This function subtracts the coatom correction from pol, which at this point should contain the value P_{xs,ys}+q.P_{x,ys}-(mu-correction) (although we can apply CoatomCorrection and MuCorrection in any order.) This means that we subtract the correcting terms corresponding to the coatoms z of ys s.t. zs < s; the corresponding subtraction is q.P_{x,z}. */ { const SchubertContext& p = schubert(); CoxNbr ys = p.shift(y,s); const CoatomList& c = p.hasse(ys); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr z = c[j]; if (p.shift(z,s) > z) /* z is not considered */ continue; if (!p.inOrder(x,z)) /* z is not in [x,ys] */ continue; /* at this point we have to do an actual subtraction */ const KLPol& p_xz = klPol(x,z); if (ERRNO) return; safeSubtract(pol[a],p_xz,1,1); if (ERRNO) { Error(ERRNO,this,x,y); ERRNO = ERROR_WARNING; return; } } return; } KLCoeff KLContext::KLHelper::computeMu(const CoxNbr& x, const CoxNbr& y) /* This function gets a previously uncomputed entry in the muList. It is based on the following remark (essentially Lusztig's "star-operation" situation). We already assume that LR(x) contains LR(y). Now let s be in LR(y), such that LR(ys) is _not_ contained in LR(x) (such an s exists iff LR(x) does not contain twoDescent(y).) Then let t be in LR(ys), not in LR(x) (and hence not in LR(y)). Then it must be so that s and t do not commute; in particular they act on the same side; assume this is on the right. So we have yst < ys < y < yt, xs < x < xt. Assume that x <= ys (otherwise mu(x,y) = mu(xs,ys)). Then from the fact that xt > x, yst < ys, exactly as in the proof of thm. 4.2. in the original k-l paper, one sees that at most four terms survive in the recursion formula : we have mu(x,y) = mu(xs,ys) + mu(xt,ys) - mu(x,yst)(if ysts < yst) - mu(xt,ys)(if xts < xt) So in all these cases we get an elementary recursion. Sets the error MU_FAIL, and returns the value undef_klcoeff, in case of failure (this can be due to memory overflow, or to coefficient over- or underflow.) */ { if (inverse(y) < y) return computeMu(inverse(x),inverse(y)); const SchubertContext& p = schubert(); LFlags f = p.twoDescent(y); if ((p.descent(x)&f) == f) { /* x is super-extremal w.r.t. y */ return recursiveMu(x,y,last(y)); } Generator s, t; /* choose s s.t. LR(ys) not contained in LR(x) */ for (LFlags f1 = p.descent(y); f1; f1 &= f1-1) { Generator u = firstBit(f1); CoxNbr yu = p.shift(y,u); LFlags fu = p.descent(yu); if ((p.descent(x)&fu) != fu) { s = u; t = firstBit(fu & ~p.descent(x)); break; } } CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); KLCoeff r1 = mu(xs,ys); if (ERRNO) goto abort; /* check if x <= ys */ if (!p.inOrder(x,ys)) { /* value is found */ status().mucomputed++; if (r1 == 0) status().muzero++; return r1; } { CoxNbr xt = p.shift(x,t); CoxNbr yst = p.shift(ys,t); /* consider four cases */ if (p.isDescent(xt,s)) { /* xts < xt */ if (p.isDescent(yst,s)) { /* ysts < yst */ KLCoeff r3 = mu(x,yst); if (ERRNO) goto abort; if (r1 < r3) { /* negative mu-coefficient */ ERRNO = MU_NEGATIVE; goto abort; } status().mucomputed++; if (r1 == r3) status().muzero++; return r1-r3; } else { /* ysts > yst */ status().mucomputed++; if (r1 == 0) status().muzero++; return r1; } } else { /* xts > xt */ if (p.isDescent(yst,s)) { /* ysts < yst */ KLCoeff r2 = mu(xt,ys); if (ERRNO) goto abort; KLCoeff r3 = mu(x,yst); if (ERRNO) goto abort; if ((r1+r2) < r3) { /* negative mu-coefficient */ ERRNO = MU_NEGATIVE; goto abort; } status().mucomputed++; if (r1+r2 == r3) status().muzero++; return r1+r2-r3; } else { /* ysts > yst */ KLCoeff r2 = mu(xt,ys); if (ERRNO) goto abort; status().mucomputed++; if (r1+r2 == 0) status().muzero++; return r1+r2; } } } abort: if (ERRNO != MEMORY_WARNING) ERRNO = MU_FAIL; return undef_klcoeff; } const KLPol* KLContext::KLHelper::fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& d_s) /* This function performs one of the main tasks in the program, namely filling in a Kazhdan-Lusztig polynomial. In this function we are not concerned with maximal efficiency, but mostly with computing as few polynomials as possible in the recursion formula. It is already assumed that x is extremal w.r.t. y. There is a tricky point about this function : since it is highly recursive, it needs to manage its workspace as a stack; this is buf. Sets the error KL_FAIL, and returns the null pointer, in case of failure. NOTE : since this function potentially triggers the allocation of many rows in the klList and in the muList (not to mention the storage of the computed polynomials), it should labor under the constraint of CATCH_MEMORY_OVERFLOW. */ { static List pol(0); const SchubertContext& p = schubert(); /* check easy cases */ Length l = p.length(y) - p.length(x); if (l < 3) { status().klcomputed++; return &(one()); } Generator s = d_s; /* If d_s is undef_generator, we compute the polynomial using descent by last term in normal form */ if (s == undef_generator) s = last(y); CoxNbr ys = p.shift(y,s); CoxNbr xs = p.shift(x,s); /* check if x is comparable to ys */ if (!p.inOrder(x,ys)) { /* return the answer recursively */ status().klcomputed++; return &klPol(xs,ys); } /* get workspace */ CATCH_MEMORY_OVERFLOW = true; Ulong a = pol.size(); pol.setSize(a+1); /* initialize the workspace to P_{xs,ys} */ const KLPol& p_xsys = klPol(xs,ys); if (ERRNO) goto abort; pol[a] = p_xsys; /* add q.P_{x,ys} */ { const KLPol& p_xys = klPol(x,ys); if (ERRNO) goto abort; safeAdd(pol[a],p_xys,1); if (ERRNO) goto abort; } /* subtract correction terms */ coatomCorrection(x,y,s,pol,a); if (ERRNO) goto abort; muCorrection(x,y,s,pol,a); if (ERRNO) goto abort; /* find address of polynomial */ { const KLPol& p_xy = *klTree().find(pol[a]); if (ERRNO) goto abort; /* return workspace and exit */ CATCH_MEMORY_OVERFLOW = false; pol.setSize(a); status().klcomputed++; return &p_xy; } abort: /* an error occurred */ CATCH_MEMORY_OVERFLOW = false; if (ERRNO != MEMORY_WARNING) ERRNO = KL_FAIL; return 0; } void KLContext::KLHelper::fillKLRow(const CoxNbr& d_y) /* This function fills the rows for y in klList and muList. It is to be called if checkKLRow(y) has returned the value false. This is one of the big functions in the program, of course. It is typically called when an element of the k-l basis of the Hecke algebra is required, or when we want to study the singularities of a Schubert variety. We have tried to optimize it for speed rather than memory efficiency. The outline of the function is as follows. Our descent strategy is to always chop off the last element in the normal form of the element under consideration, as provided by d_last. This is much better than taking, say, the first descent. - it is assumed that the rows in klList and muList corresponding to the descent path that comes from our descent strategy (and the fact that sometimes we move over to inverses) have been allocated; this can be assomplished by calling allocRowComputation. This condition will then also hold for the elements in the descent path. - then, we fill the corresponding rows, starting from the identity; the nice thing here is that it will always be guaranteed that P_{xs,ys}, P_{x,ys} and the mu(z,ys) are available; this is a recursive call to fillKLRow, except that we can be sure that the rows have been allocated already. - then, we run through muList(ys), which has been filled, and determine the z for which mu(z,ys) != 0, and zs < z; these are the terms which cause corrections. For each such z, we call fillKLRow(z). - we do the same for the coatom list of y; - now, we are certain that all the terms we need for all the P_{x,y} in klList(y) are available. To avoid having to test the condition x <= z in the correction terms, we compute them all at once; again we run through the list of z's as above, and for all x <= z which is extremal w.r.t. the descent set of y, do the required subtraction. So we will work with a large vector of KLCoeff's, and need a table of offsets to the corresponding polynomials. One nice thing of this setup is that the work on the rows for y starts only when all the preparations are finished; it is guaranteed that there will not be any recursive calls in the duration of this filling. So, contrary to the fillKLPol function, workspace doesn't have to be managed as a stack. Returns the error ERROR_WARNING in case of failure, after printing an error message. */ { static List pol(0); const SchubertContext& p = schubert(); CoxNbr y = d_y; if (y == 0) return; if (inverse(y) < y) /* fill in the row for inverse(y) */ y = inverse(y); /* recursively fill in rows in the descent path */ Generator s = last(y); CoxNbr ys = p.rshift(y,s); if (!checkKLRow(ys)) { fillKLRow(ys); if (ERRNO) goto abort; } /* make sure the correcting terms are available */ prepareRow(y,s); if (ERRNO) goto abort; /* prepare workspace; pol holds the row of polynomials; initialize workspace with P_{xs,ys} */ initWorkspace(y,pol); /* add q.P_{x,ys} when appropriate */ secondTerm(y,pol); if (ERRNO) goto abort; /* subtract correcting terms */ muCorrection(y,pol); if (ERRNO) goto abort; coatomCorrection(y,pol); if (ERRNO) goto abort; /* copy results to row */ writeKLRow(y,pol); if (ERRNO) goto abort; return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::fillMuRow(MuRow& row, const CoxNbr& y) /* Fills row with the values for the mu(x,y). It is assumed that the row has been correctly allocated (i.e., that it holds only extremal entries with odd length difference > 1 w.r.t. y, and at least one entry for each non-zero mu.) */ { for (Ulong j = 0; j < row.size(); ++j) { if (row[j].mu == undef_klcoeff) { CoxNbr x = row[j].x; row[j].mu = computeMu(x,y); if (ERRNO) return; } } return; } void KLContext::KLHelper::initWorkspace(const CoxNbr& y, List& pol) /* This function sets pol to a row of one polynomial for each x in klList(y), and initializes the corresponding pol[j] to klPol(xs,ys). */ { const SchubertContext& p = schubert(); const ExtrRow& e = extrList(y); pol.setSize(e.size()); if (ERRNO) goto abort; /* initialize with values P_{xs,ys} */ { Generator s = last(y); CoxNbr ys = p.rshift(y,s); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr xs = p.shift(e[j],s); pol[j] = klPol(xs,ys); if (ERRNO) goto abort; } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::inverseMuRow(const CoxNbr& y) /* This function constructs the mu-row for the inverse of y from that of y. It is assumed that the row for inverse(y) is filled in, and that y is not equal to its inverse. We delete the row for y, since it will be faster to reconstruct it in any case than to extract the non-computed values from the inverse list. */ { CoxNbr yi = inverse(y); if (isMuAllocated(yi)) { /* deallocate; update status */ MuRow& m = muList(yi); for (Ulong j = 0; j < m.size(); ++j) { KLCoeff mu = m[j].mu; if (mu != undef_klcoeff) status().mucomputed--; if (mu == 0) status().muzero--; } status().munodes -= m.size(); delete &m; } d_kl->d_muList[yi] = new MuRow(muList(y)); MuRow& m = muList(yi); for (Ulong j = 0; j < m.size(); ++j) { m[j].x = inverse(m[j].x); } m.sort(); /* update status */ for (Ulong j = 0; j < m.size(); ++j) { KLCoeff mu = m[j].mu; if (mu != undef_klcoeff) status().mucomputed++; if (mu == 0) status().muzero++; } status().munodes += m.size(); return; } void KLContext::KLHelper::makeMuRow(const CoxNbr& y) /* This function makes a row in the mu-table from scratch (i.e., it is assumed that isMuAllocated(y) = false). The idea is to do the minimal allocation (i.e., write down non-zero mu's only), and to compute as much as possible within the mu-table itself. This function is crucial to the optimal determination of the W-graph of the group, so a lot of care has been expended onto it. One crucial property of the mu-function is its stability under *-operations. Otherwise, one should remark that in the recursive formula for mu(x,y), there is just one term (the one coming from q.P_{x,ys}) that is not already a mu-value; and it will be a mu-value if x moves up under the descent set of ys. So the only entries that have to be computed are the ones that are extremal w.r.t. *-operations, and we will only need the highest-degree term of some kl-pols with even length-difference. NOTE : to be implemented! */ {} void KLContext::KLHelper::muCorrection(const CoxNbr& y, List& pol) /* This function subtracts the term P_{x,z}mu(z,ys) from the appropriate entry in pol. The idea is to extract [e,z] and run through it, so that we avoid calls to inOrder entirely. */ { const SchubertContext& p = schubert(); const ExtrRow& e = extrList(y); Generator s = last(y); CoxNbr ys = p.rshift(y,s); const MuRow& mu_row = muList(ys); for (Ulong j = 0; j < mu_row.size(); ++j) { if (mu_row[j].mu == 0) continue; CoxNbr z = mu_row[j].x; Length h = mu_row[j].height; KLCoeff mu_value = mu_row[j].mu; if (p.shift(z,s) > z) continue; BitMap b(size()); p.extractClosure(b,z); maximize(p,b,p.descent(y)); Ulong i = 0; BitMap::Iterator b_end = b.end(); for (BitMap::Iterator k = b.begin(); k != b_end; ++k) { CoxNbr x = *k; while (e[i] < x) ++i; safeSubtract(pol[i],klPol(x,z),mu_value,h+1); if (ERRNO) { Error(ERRNO,this,x,y); ERRNO = ERROR_WARNING; return; } } } return; } void KLContext::KLHelper::muCorrection(const CoxNbr& d_x, const CoxNbr& y, const Generator& d_s, List& pol, const Ulong& a) /* This function subtracts from pol the correction terms P_{x,z}.mu(z,ys)q^{(l(y)-l(z))/2} corresponding to the z in [x,ys] s.t. mu(z,ys) != 0, zs < z, and l(ys)-l(z) >= 3; the correction for the coatoms in [x,ys] is dealt with in the function coatomCorrection. NOTE : as usual, we watch out for memory overflow --- it is assumed that CATCH_MEMORY_OVERFLOW is turned on. Overflow in the coefficients cannot occur during subtraction; however, we set an error if a negative coefficient is found, as this would be a major discovery! */ { const SchubertContext& p = schubert(); CoxNbr x = d_x; Generator s = d_s; CoxNbr ys = p.shift(y,s); if (!isMuAllocated(ys)) { /* allocate row */ allocMuRow(ys); if (ERRNO) goto abort; } { MuRow& m = muList(ys); { Length ly = p.length(y); for (Ulong j = 0; j < m.size(); ++j) { CoxNbr z = m[j].x; if (p.shift(z,s) > z) continue; if (!p.inOrder(x,z)) continue; /* compute the mu-coefficient if it was not already computed */ if (m[j].mu == undef_klcoeff) { m[j].mu = computeMu(z,ys); if (ERRNO) goto abort; } /* subtract the correction if mu(z,ys) != 0 */ if (m[j].mu) { Length h = (ly - p.length(m[j].x))/2; const KLPol& p_xz = klPol(x,z); if (ERRNO) goto abort; safeSubtract(pol[a],p_xz,m[j].mu,h); if (ERRNO) goto abort; } } } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::prepareRow(const CoxNbr& y, const Generator& d_s) /* This function prepares for the filling of row y in klList and muList, by making sure that all the correction terms are available. It is assumed that fillKLRow(ys) has already been called. Deals with the error if it occurs, and sets the error ERROR_WARNING; */ { const SchubertContext& p = schubert(); Generator s = d_s; CoxNbr ys = p.shift(y,s); if (!checkMuRow(ys)) { if (inverse(ys) < ys) { readMuRow(inverse(ys)); inverseMuRow(inverse(ys)); } else readMuRow(ys); } const MuRow& mu_row = muList(ys); for (Ulong j = 0; j < mu_row.size(); ++j) { if (mu_row[j].mu == 0) continue; CoxNbr z = mu_row[j].x; if (p.shift(z,s) > z) continue; if (!checkKLRow(z)) { allocRowComputation(z); if (ERRNO) goto abort; fillKLRow(z); if (ERRNO) goto abort; } } { const CoatomList& c = p.hasse(ys); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr z = c[j]; if (p.shift(z,s) > z) continue; if (!checkKLRow(z)) { allocRowComputation(z); if (ERRNO) goto abort; fillKLRow(z); if (ERRNO) goto abort; } } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::readMuRow(const CoxNbr& y) /* This function fills the mu-row from the corresponding kl-row. If the row has not been allocated yet, it makes sure that no unnecessary allocations are made. */ { const SchubertContext& p = schubert(); const KLRow& kl_row = klList(y); const ExtrRow& e_row = extrList(y); if (!isMuAllocated(y)) { /* make row from scratch */ MuRow mu_buf(0); mu_buf.setSizeValue(0); Length ly = p.length(y); for (Ulong j = 0; j < kl_row.size(); ++j) { CoxNbr x = e_row[j]; Length lx = p.length(x); if ((ly-lx)%2 == 0) continue; if ((ly-lx) == 1) continue; const KLPol& pol = *kl_row[j]; Degree d = (ly-lx-1)/2; if (pol.deg() < d) continue; MuData m(x,pol[d],d); mu_buf.append(m); if (ERRNO) goto abort; } d_kl->d_muList[y] = new MuRow(mu_buf); if (ERRNO) goto abort; status().munodes += mu_buf.size(); status().mucomputed += mu_buf.size(); status().murows++; } else { Ulong i = 0; MuRow& mu_row = muList(y); for (Ulong j = 0; j < muList(y).size(); ++j) { MuData& mu = mu_row[j]; CoxNbr x = mu.x; while(e_row[i] < x) ++i; const KLPol& pol = *kl_row[i]; Length d = mu.height; if (pol.deg() == d) mu.mu = pol[d]; else { mu.mu = 0; status().muzero++; } status().mucomputed++; } } return; abort: Error(ERRNO); ERRNO = MEMORY_WARNING; return; } KLCoeff KLContext::KLHelper::recursiveMu(const CoxNbr& d_x, const CoxNbr& y, const Generator& d_s) /* This function computes mu(x,y) using the general recursive formula for the descent s. In practice, this will be used only if the descent set of x contains the _second_ descent set of y. It is assumed that x < y x extremal w.r.t. y, and l(y)-l(x) odd > 1. Sets the error MU_FAIL, and returns the value undef_klcoeff, in case of failure (this can be due to memory overflow, or to coefficient over- or underflow.) */ { const SchubertContext& p = schubert(); CoxNbr x = d_x; Generator s = d_s; Length l = p.length(y) - p.length(x); /* l is odd > 1 */ CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); KLCoeff r = mu(xs,ys); if (ERRNO) goto abort; if (!p.inOrder(x,ys)) { /* value is found */ status().mucomputed++; if (r == 0) status().muzero++; return r; } /* special case when the length difference is three */ if (l == 3) { /* P_{x,ys} = 1 */ safeAdd(r,1); if (ERRNO) { /* overflow; highly unlikely! */ Error(MU_OVERFLOW,this,x,y); goto abort; } goto coatom_correction; } /* get the term from q.P_{x,ys} */ { CoxNbr x1 = p.maximize(x,p.descent(ys)); if (x != x1) { // no polynomial is needed; does not happen in double // extremal case if (p.length(x1) == p.length(x) + 1) // no correction otherwise r += mu(x1,ys); } else { /* we need a polynomial */ const KLPol& pol = klPol(x,ys); if (ERRNO) goto abort; Degree d = (l-1)/2 - 1; if (pol.deg() == d) { safeAdd(r,pol[d]); if (ERRNO) { /* overflow; highly unlikely! */ Error(MU_OVERFLOW,this,x,y); goto abort; } } } } /* subtract correction terms where l(ys) - l(z) > 1 */ { if (!isMuAllocated(ys)) { /* allocate row */ allocMuRow(ys); if (ERRNO) goto abort; } MuRow& m = muList(ys); for (Ulong j = 0; j < m.size(); ++j) { CoxNbr z = m[j].x; if (z == x) continue; if (p.shift(z,s) > z) continue; if (!p.inOrder(x,z)) continue; /* fill in the mu-coefficient if it was not already computed */ if (m[j].mu == undef_klcoeff) { m[j].mu = computeMu(z,ys); if (ERRNO) goto abort; } /* subtract the correction if mu(z,ys) != 0 */ if (m[j].mu) { KLCoeff r1 = mu(x,z); if (ERRNO) goto abort; safeMultiply(r1,m[j].mu); if (ERRNO) { /* overflow; highly unlikely! */ Error(MU_OVERFLOW,this,x,y); goto abort; } klsupport::safeSubtract(r,r1); if (ERRNO) { /* negative coefficient */ Error(MU_NEGATIVE,this,x,y); goto abort; } } } } coatom_correction: /* subtract the coatom correction */ { const CoatomList& c = p.hasse(ys); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr z = c[j]; CoxNbr zs = p.shift(z,s); if (zs > z) continue; if (!p.inOrder(x,z)) continue; KLCoeff r1 = mu(x,z); if (ERRNO) goto abort; klsupport::safeSubtract(r,r1); if (ERRNO) { /* negative coefficient */ Error(MU_NEGATIVE,this,x,y); goto abort; } } } status().mucomputed++; if (r == 0) status().muzero++; return r; abort: if (ERRNO != MEMORY_WARNING) ERRNO = MU_FAIL; return undef_klcoeff; } void KLContext::KLHelper::secondTerm(const CoxNbr& y, List& pol) /* This function takes care of the "second term" q.P_{x,ys} in the recursion formula for P_{x,y}. It is assumed that y <= inverse(y) and that the descent strategy is via last. Here all the memory allocations have been made successfully; the only cause of error would be an overflow condition. In that case, the error is treated and ERROR_WARNING is set. Since we want to avoid all calls to InOrder, the method here is to extract [e,ys], extremalize it w.r.t. the descent set of y, and run through it and make the correction. */ { const SchubertContext& p = schubert(); BitMap b(0); Generator s = last(y); CoxNbr ys = p.rshift(y,s); /* extract [e,ys] */ p.extractClosure(b,ys); /* extremalize w.r.t. y */ maximize(p,b,p.descent(y)); /* add to appropriate terms */ Ulong i = 0; BitMap::Iterator b_end = b.end(); const ExtrRow& e = extrList(y); for (BitMap::Iterator j = b.begin(); j != b_end; ++j) { CoxNbr x = *j; while(e[i] < x) ++i; safeAdd(pol[i],klPol(x,ys),1); if (ERRNO) { Error(ERRNO,this,x,y); ERRNO = ERROR_WARNING; return; } } return; } void KLContext::KLHelper::writeKLRow(const CoxNbr& y, List& pol) /* This function writes the polynomials from the list pol to klList(y); more precisely, it finds their adresses in klTree(), and writes those to klList(y). First it has to put the true degrees in the pol[j]. It is assumed that y <= inverse(y). The only error that can occur here is memory overflow because of the allocation for new polynomials in klTree(). In that case, the error is treated, and ERROR_WARNING is set. */ { KLRow& kl_row = klList(y); for (Ulong j = 0; j < kl_row.size(); ++j) { if (kl_row[j]) continue; /* find degree of polynomial */ Degree d = pol[j].deg(); for (; d; --d) { if (pol[j][d]) break; } pol[j].setDeg(d); const KLPol* q = klTree().find(pol[j]); if (q == 0) { /* an error occurred */ Error(ERRNO); ERRNO = ERROR_WARNING; return; } kl_row[j] = q; status().klcomputed++; } return; } void KLContext::KLHelper::writeMuRow(const MuRow& row, const CoxNbr& y) /* This function copies row to the corresponding row in the mu-list. The idea is to copy only the non-zero entries. */ { /* count non-zero entries */ Ulong count = 0; for (Ulong j = 0; j < row.size(); ++j) { if (row[j].mu != 0) count++; } MuRow& y_row = muList(y); y_row.setSize(count); if (ERRNO) { Error(ERRNO); ERRNO = ERROR_WARNING; return; } count = 0; for (Ulong j = 0; j < row.size(); ++j) { if (row[j].mu != 0) { new(y_row.ptr()+count) MuData(row[j].x,row[j].mu,row[j].height); count++; } } status().munodes += count; status().murows++; return; } }; /**************************************************************************** Chapter III -- The MuFilter class The MuFilter class is a small functor, useful for adapting iterators when constructing mu-lists. It filters out elements according to length parity and length difference (the intention is to use it with the FilteredIterator adaptor.) ****************************************************************************/ namespace kl { MuFilter::MuFilter(const SchubertContext& p, const Length& l) :d_p(p), d_l(l) {} MuFilter::MuFilter(const SchubertContext& p, const CoxNbr& y) :d_p(p) { d_l = d_p.length(y); } MuFilter::~MuFilter() {} }; /**************************************************************************** Chapter IV -- KLStatus This section defines the functions declared for the KLStatus structure : - KLStatus() : constructor; - ~KLStatus() : destructor; ****************************************************************************/ namespace kl { KLStatus::KLStatus() :klrows(0), klnodes(0), klcomputed(0), murows(0), munodes(0), mucomputed(0), muzero(0) {} KLStatus::~KLStatus() {} }; /**************************************************************************** Chapter V -- Input/Output This section defines the input/output functions declared in kl.h : - print(file,h) : prints a homology vector; - printMuTable(file,kl) : prints the full mu-table; - showKLPol(file,kl,x,y) : maps out the computation of P_{x,y}; - showMu(file,kl,x,y) : maps out the computation of mu(x,y); - showSimpleMu(file,kl,x,y) : auxiliary to ShowMu; - showRecursiveMu(file,kl,x,y) : auxiliary to ShowMu; ****************************************************************************/ namespace kl { void print(FILE* file, const Homology& h) /* Prints the homology vector as a single long line. */ { if (h.size()) /* print first term */ fprintf(file," h[0] = %lu",h[0]); for (Ulong j = 1; j < h.size(); ++j) { fprintf(file," h[%lu] = %lu",j,h[j]); } return; } void printMuTable(FILE* file, const KLContext& kl, const Interface& I) /* This function prints ou the contents of the mu-table. It prints only the entries for which mu(x,y) != 0 (and of course, for which l(y)-l(x)>1; the others are gotten from the coatom table.) */ { const SchubertContext& p = kl.schubert(); for (CoxNbr y = 0; y < p.size(); ++y) { kl.print(file,y,I); fprintf(file," : "); const MuRow& row = kl.muList(y); Ulong count = 0; for (Ulong j = 0; j < row.size(); ++j) { const MuData& mu = row[j]; if (mu.mu == 0) continue; if (count) fprintf(file,","); count++; fprintf(file,"{"); fprintf(file,"x = "); kl.print(file,mu.x,I); fprintf(file,", mu = %lu, height = %lu",static_cast(mu.mu), static_cast(mu.height)); fprintf(file,"}"); } fprintf(file,"\n"); } return; } void showKLPol(FILE* file, KLContext& kl, const CoxNbr& d_x, const CoxNbr& d_y, const Interface& I, const Generator& d_s) /* This function prints out the various terms appearing in the computation of the Kazhdan-Lusztig polynomial P_{x,y} through the standard recursion formula, using the generator s as descent generator. It is assumed that x <= y in the Bruhat order, and that s is indeed a descent generator for y. */ { static String buf(0); const SchubertContext& p = kl.schubert(); CoxNbr x = d_x; CoxNbr y = d_y; Generator s = d_s; const KLPol& pol = kl.klPol(x,y,s); if (ERRNO) { Error (ERRNO); return; } unsigned long ls = LINESIZE; reset(buf); append(buf,"x = "); p.append(buf,x,I); append(buf,"; y = "); p.append(buf,y,I); append(buf," L:"); append(buf,p.ldescent(y),I); append(buf," R:"); append(buf,p.rdescent(y),I); foldLine(file,buf,ls,0,"yL"); fprintf(file,"\n\n"); if (kl.inverse(y) < y) { // go over to inverses x = kl.inverse(x); y = kl.inverse(y); fprintf(file,"inverse(y) < y\n"); fprintf(file,"new x : "); p.print(file,x,I); fprintf(file,"\nnew y : "); p.print(file,y,I); fprintf(file,"\n\n"); } LFlags f = p.descent(y); x = p.maximize(x,f); if (x > d_x) { fprintf(file,"x is not extremal w.r.t. y\nnew x: "); p.print(file,x,I); fprintf(file,"\n\n"); } Length d = p.length(y) - p.length(x); if (d < 3) { /* trivial case */ fprintf(file,"l(y)-l(x) < 3\n\n"); goto end; } { if (s == undef_generator) s = kl.last(y); CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); if (!p.inOrder(x,ys)) { /* easy case */ if (s < kl.rank()) { /* action is on the right */ fprintf(file,"x not comparable to ys for s = %d\n",s+1); reset(buf); append(buf,"xs = "); p.append(buf,xs,I); append(buf,"; ys = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"y"); fprintf(file,"\n\n"); goto end; } else { /* action is on the left */ fprintf(file,"x not comparable to sy for s = %d\n",s+1-kl.rank()); reset(buf); append(buf,"sx = "); p.append(buf,xs,I); append(buf,"; sy = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"s"); fprintf(file,"\n\n"); goto end; } } /* apply recursion formula */ if (s < kl.rank()) { fprintf(file,"applying recursion formula with s = %d on the right\n\n", s+1); reset(buf); append(buf,"xs = "); p.append(buf,xs,I); append(buf,"; ys = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"y"); fprintf(file,"\n\n"); } else { fprintf(file,"applying recursion formula with s = %d on the left\n\n", s+1-kl.rank()); reset(buf); append(buf,"sx = "); p.append(buf,xs,I); append(buf,"; sy = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"s"); fprintf(file,"\n\n"); } /* first term */ reset(buf); if (s < kl.rank()) { append(buf,"P_{xs,ys} = "); append(buf,kl.klPol(xs,ys),"q"); } else { append(buf,"P_{sx,sy} = "); append(buf,kl.klPol(xs,ys),"q"); } foldLine(file,buf,ls,4,"+"); fprintf(file,"\n"); /* second term */ reset(buf); if (s < kl.rank()) { append(buf,"P_{x,ys} = "); append(buf,kl.klPol(x,ys),"q"); } else { append(buf,"P_{x,sy} = "); append(buf,kl.klPol(x,ys),"q"); } foldLine(file,buf,ls,4,"+"); fprintf(file,"\n\n"); /* coatom correction */ const CoatomList& c = p.hasse(ys); bool coatomcorrection = false; for (Ulong j = 0; j < c.size(); ++j) { CoxNbr z = c[j]; if (p.shift(z,s) > z) continue; if (!p.inOrder(x,z)) continue; coatomcorrection = true; reset(buf); io::append(buf,"z = "); p.append(buf,z,I); io::append(buf," P_{x,z} = "); polynomials::append(buf,kl.klPol(x,z),"q"); foldLine(file,buf,ls,4,"P+"); fprintf(file,"\n"); } if (coatomcorrection) fprintf(file,"\n"); /* mu correction */ const MuRow& m = kl.muList(ys); Length l_ys = p.length(ys); bool mucorrection = false; for (Ulong j = 0; j < m.size(); ++j) { CoxNbr z = m[j].x; if (p.shift(z,s) > z) continue; if (!p.inOrder(x,z)) continue; if (m[j].mu) { mucorrection = true; reset(buf); io::append(buf,"z = "); p.append(buf,z,I); pad(buf,l_ys+1); /* remember the four characters "z = " */ io::append(buf," mu = "); append(buf,m[j].mu); io::append(buf," height = "); append(buf,m[j].height); io::append(buf," P_{x,z} = "); append(buf,kl.klPol(x,z),"q"); foldLine(file,buf,ls,4,"Pmh+"); fprintf(file,"\n"); } } if (mucorrection) fprintf(file,"\n"); } end: reset(buf); io::append(buf,"result : "); append(buf,pol,"q"); if (2*pol.deg()+1 == d) io::append(buf," *"); foldLine(file,buf,ls,4,"+"); fprintf(file,"\n\n"); return; } void showMu(FILE* file, KLContext& kl, const CoxNbr& d_x, const CoxNbr& y, const Interface& I) /* Maps out the computation of a mu-coefficient. See KLContext::KLHelper::computeMu for the algorithm. */ { static String buf(0); const SchubertContext& p = kl.schubert(); CoxNbr x = d_x; KLCoeff r = kl.mu(x,y); if (ERRNO) goto abort; { unsigned long ls = LINESIZE; reset(buf); append(buf,"x = "); p.append(buf,x,I); append(buf," y = "); p.append(buf,y,I); append(buf," L:"); append(buf,p.ldescent(y),I); append(buf," R:"); append(buf,p.rdescent(y),I); foldLine(file,buf,ls,0,"yL"); fprintf(file,"\n\n"); LFlags fy = p.descent(y); x = p.maximize(x,fy); if (x > d_x) { fprintf(file,"x is not extremal w.r.t. y\n\nresult: 0\n\n"); return; } Length d = p.length(y) - p.length(x); if ((d%2) == 0) { fprintf(file,"even length difference\n\nresult: 0\n\n"); return; } if (d == 1) { /* trivial case */ fprintf(file,"x is coatom of y\n\nresult: 1\n\n"); return; } LFlags f2 = p.twoDescent(y); LFlags fx = p.descent(x); if ((fx&f2) != f2) { /* recursion case */ fprintf(file,"x is not doubly extremal w.r.t. y\n\n"); showSimpleMu(file,kl,x,y,r,I); return; } fprintf(file,"x is doubly extremal w.r.t. y\n\n"); showRecursiveMu(file,kl,x,y,r,I); return; } abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } }; namespace { void showRecursiveMu(FILE* file, KLContext& kl, const CoxNbr& d_x, const CoxNbr& y, const KLCoeff& r, const Interface& I) /* Maps out the computation in the case where the recursion formula has to be used. */ { static String buf(0); const SchubertContext& p = kl.schubert(); unsigned long ls = LINESIZE; CoxNbr x = d_x; Generator s = kl.last(y); Length l = p.length(y) - p.length(x); /* l is odd > 1 */ CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); if (!p.inOrder(x,ys)) { // mu(x,y) = mu(xs,ys) if (s < kl.rank()) { // action is on the right fprintf(file,"x not comparable to ys for s = %d\n",s+1); reset(buf); append(buf,"xs = "); p.append(buf,xs,I); append(buf,"; ys = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"y"); fprintf(file,"\n\nresult : %lu\n\n",static_cast(r)); } else { // action is on the left fprintf(file,"x not comparable to sy for s = %d\n",s-kl.rank()+1); reset(buf); append(buf,"sx = "); p.append(buf,xs,I); append(buf,"; sy = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"s"); fprintf(file,"\n\n"); fprintf(file,"\n\nresult : %lu\n\n",static_cast(r)); } return; } // if we get to this point, w need to apply the full recursion formula if (s < kl.rank()) { fprintf(file,"applying recursion formula with s = %d on the right\n\n", s+1); reset(buf); append(buf,"xs = "); p.append(buf,xs,I); append(buf,"; ys = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"y"); fprintf(file,"\n\n"); } else { fprintf(file,"applying recursion formula with s = %d on the left\n\n", s+1-kl.rank()); reset(buf); append(buf,"sx = "); p.append(buf,xs,I); append(buf,"; sy = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"s"); fprintf(file,"\n\n"); } // first term reset(buf); if (s < kl.rank()) { fprintf(file,"mu(xs,ys) = %lu\n",static_cast(kl.mu(xs,ys))); } else { fprintf(file,"mu(sx,sy) = %lu\n",static_cast(kl.mu(xs,ys))); } // second term reset(buf); const KLPol& pol = kl.klPol(x,ys); KLCoeff r1 = 0; Degree d = (l-1)/2 - 1; if (pol.deg() == d) { r1 = pol[d]; } if (s < kl.rank()) { fprintf(file,"second term is %lu\n",static_cast(r1)); } else { fprintf(file,"second term is %lu\n",static_cast(r1)); } fprintf(file,"\n"); // coatom correction const CoatomList& c = p.hasse(ys); bool coatomcorrection = false; for (Ulong j = 0; j < c.size(); ++j) { CoxNbr z = c[j]; if (p.shift(z,s) > z) continue; if (!p.inOrder(x,z)) continue; coatomcorrection = true; reset(buf); io::append(buf,"z = "); p.append(buf,z,I); io::append(buf," mu(x,z) = "); io::append(buf,kl.mu(x,z)); foldLine(file,buf,ls,4," "); fprintf(file,"\n"); } if (coatomcorrection) fprintf(file,"\n"); // mu-correction const MuRow& m = kl.muList(ys); Length l_ys = p.length(ys); bool mucorrection = false; for (Ulong j = 0; j < m.size(); ++j) { CoxNbr z = m[j].x; if (p.shift(z,s) > z) continue; if (!p.inOrder(x,z)) continue; // fill in the mu-coefficient if it was not already computed if (m[j].mu == undef_klcoeff) { kl.mu(z,ys); // this will fill m[j].mu if (ERRNO) { Error(ERRNO); return; } } if (m[j].mu) { mucorrection = true; reset(buf); io::append(buf,"z = "); p.append(buf,z,I); pad(buf,l_ys+1); // remember the four characters "z = " io::append(buf," mu = "); append(buf,m[j].mu); io::append(buf," height = "); append(buf,m[j].height); io::append(buf," mu(x,z) = "); append(buf,kl.mu(x,z)); foldLine(file,buf,ls,4," "); fprintf(file,"\n"); } } if (mucorrection) fprintf(file,"\n"); // print result : fprintf(file,"result : %lu\n\n",static_cast(r)); return; } void showSimpleMu(FILE* file, KLContext& kl, const CoxNbr& x, const CoxNbr& y, const KLCoeff& r, const Interface& I) /* Auxiliary to ShowMu. Maps out the computation of a mu-coefficient in the case where there is a direct recursion. It is assumed that the computation proper has already been tried with success. */ { static String buf(0); const SchubertContext& p = kl.schubert(); unsigned long ls = LINESIZE; Generator s,t; for (LFlags f1 = p.descent(y); f1; f1 &= f1-1) { Generator u = firstBit(f1); CoxNbr yu = p.shift(y,u); LFlags fu = p.descent(yu); if ((p.descent(x)&fu) != fu) { s = u; t = firstBit(fu & ~p.descent(x)); break; } } fprintf(file,"using descent s = %lu and ascent t = %lu\n\n", static_cast(s+1),static_cast(t+1)); CoxNbr xs = p.shift(x,s); CoxNbr ys = p.shift(y,s); CoxNbr xt = p.shift(x,t); CoxNbr yst = p.shift(ys,t); /* consider four cases */ reset(buf); if (p.descent(xt) & lmask[s]) { /* xts < xt */ append(buf,"xs = "); p.append(buf,xs,I); append(buf," ys = "); p.append(buf,ys,I); if (p.descent(yst) & lmask[s]) { /* ysts < yst */ append(buf," yst = "); p.append(buf,yst,I); foldLine(file,buf,ls,0,"xy"); fprintf(file,"\n\n"); fprintf(file, "result is mu(xs,ys)-mu(x,yst) = %lu - %lu = %lu\n\n", static_cast(kl.mu(xs,ys)), static_cast(kl.mu(x,yst)), static_cast(r)); return; } else { /* ysts > yst */ foldLine(file,buf,ls,0,"xy"); fprintf(file,"\n\n"); fprintf(file,"result is mu(xs,ys) = %lu\n\n",static_cast(r)); return; } } else { /* xts > xt */ if (p.descent(yst) & lmask[s]) { /* ysts < yst */ append(buf,"xs = "); p.append(buf,xs,I); append(buf," xt = "); p.append(buf,xt,I); append(buf," ys = "); p.append(buf,ys,I); append(buf," yst = "); p.append(buf,yst,I); foldLine(file,buf,ls,0,"xy"); fprintf(file,"\n\n"); fprintf(file, "result is mu(xs,ys)+mu(xt,ys)-mu(x,yst) = %lu + %lu - %lu = %lu\n\n", static_cast(kl.mu(xs,ys)), static_cast(kl.mu(xt,ys)), static_cast(kl.mu(x,yst)), static_cast(r)); return; } else { /* ysts > yst */ if (p.descent(xs) & lmask[t]) { append(buf,"xs = "); p.append(buf,xs,I); append(buf," xt = "); p.append(buf,xt,I); append(buf," ys = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"xy"); fprintf(file,"\n\n"); fprintf(file,"result is mu(xs,ys)+mu(xt,ys) = %lu + %lu = %lu\n\n", static_cast(kl.mu(xs,ys)), static_cast(kl.mu(xt,ys)), static_cast(r)); return; } else { /* mu(xs,ys) = 0 */ append(buf,"xt = "); p.append(buf,xt,I); append(buf," ys = "); p.append(buf,ys,I); foldLine(file,buf,ls,0,"xy"); fprintf(file,"\n\n"); fprintf(file,"result is mu(xt,ys) = %lu\n\n", static_cast(r)); return; } } } return; } }; /**************************************************************************** Chapter VI -- Singularities This section provides some functions for the study of the (rational) singular locus of Schubert varieties. These functions can be defined for arbitrary Coxeter groups, but of course the geometrical interpretation only makes sense when the Schubert variety is known to exist. The following functions are defined : - genericSingularities(h,y,kl) : returns the singular locus; - isSingular(row) : checks rational singularity; The function singularStratification has been moved (perhaps mistakenly) to hecke.cpp. *****************************************************************************/ namespace kl { void genericSingularities(HeckeElt& h, const CoxNbr& y, KLContext& kl) /* This function returns in h the singular locus of cl(X_y). The point is to do this while computing as few k-l polynomials as possible. */ { const SchubertContext& p = kl.schubert(); BitMap b(p.size()); BitMap bs(p.size()); p.extractClosure(b,y); maximize(p,b,p.descent(y)); h.setSize(0); for (BitMap::ReverseIterator x = b.rbegin(); x != b.rend(); ++x) { const KLPol& pol = kl.klPol(*x,y); if (ERRNO) return; if (pol.deg() > 0) { /* remove [e,x[ */ HeckeMonomial m(*x,&pol); h.append(m); p.extractClosure(bs,*x); CoxNbr x1 = *x; /* *x will not be correct anymore after modification */ b.andnot(bs); b.setBit(x1); /* needed to make the decrement correct */ } } h.reverse(); return; } bool isSingular(const HeckeElt& h) /* This function answers yes if one of the polynomials in the row is distinct from one, no otherwise. This is equivalent to rational singularity of the Schubert variety, when such a geometric context is defined, and the row is the extremal row for an element y. NOTE : conjecturally, annulation of the term corresponding to the extremalization of the origin ensures annulation of all the others. */ { for (Ulong j = 0; j < h.size(); ++j) { const KLPol& pol = h[j].pol(); if (pol.deg() != 0) return true; } return false; } bool isSingular(const KLRow& row) /* This function answers yes if one of the polynomials in the row is distinct from one, no otherwise. This is equivalent to rational singularity of the Schubert variety, when such a geometric context is defined, and the row is the extremal row for an element y. */ { for (Ulong j = 0; j < row.size(); ++j) { const KLPol* pol = row[j]; if (pol->deg() != 0) return true; } return false; } }; /**************************************************************************** Chapter VII -- Homology vectors This section contains code for the computation of homology vectors. For now, we follow a simple-minded approach, making the vector element-wise. Something more sophisticated could be done, using the orbits in the Schubert closure under the action of the descent set of y; this would involve recognizing types of finite groups and such things. The following functions are defined : - ihBetti(h,kl,row) : puts the IH betti numbers of row in h; *****************************************************************************/ namespace kl { void ihBetti(Homology& h, const CoxNbr& y, KLContext& kl) /* This function puts the IH betti numbers of the row in h, in a simple-minded approach. There is a serious danger of overflow here. For now, we set the value to undef_coxsize in case of overflow; this should be improved of course if it happens too often, using long integers for instance. */ { const SchubertContext& p = kl.schubert(); BitMap b(0); p.extractClosure(b,y); h.setSize(p.length(y)+1); h.setZero(); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator x = b.begin(); x != b_end; ++x) { const KLPol& pol = kl.klPol(*x,y); Length d = p.length(*x); for (Ulong i = 0; i <= pol.deg(); ++i) { if (h[d+i] > COXSIZE_MAX - pol[i]) h[d+i] = undef_coxnbr; else h[d+i] += pol[i]; } } return; } }; /**************************************************************************** Chapter VIII -- Kazhdan-Lustig bases. This section defines functions returning Kazhdan-Lusztig bases. Note that the coefficients of these bases should actually be Laurent polynomials; however we (perhaps mistakenly) leave it for now to the output functions to do the shifting that is required; this saves us from introducing a new type at this point. The following functions are defined : - cBasis(h,y,kl) : also called sometimes the C'-basis; in our opinion, the right choice of basis; ****************************************************************************/ namespace kl { void cBasis(HeckeElt& h, const CoxNbr& y, KLContext& kl) /* This is what in the original Kazhdan-Lusztig paper is called the C'-basis, but is now usually denoted c. The C-basis from the K-L paper doesn't seem worth implementing. */ { const SchubertContext& p = kl.schubert(); BitMap b(0); p.extractClosure(b,y); BitMap::Iterator b_end = b.end(); h.setSize(0); for (BitMap::Iterator x = b.begin(); x != b_end; ++x) { const KLPol& pol = kl.klPol(*x,y); HeckeMonomial m(*x,&pol); h.append(m); } return; } }; /**************************************************************************** Chapter IX -- Utility functions This section defines some utility functions used in this module : - allocExtrRow(kl,row,y) : does the allocation of the row for y, in row; - appendStar(str,kl,x,pol,l) : appends a star if mu != 0; - find(row,x) : finds x in an extremal row (for KLRow or MuRow); - permuteValues(kl,q) : permutes the values of tables in kl; - permuteRanges(kl,q) : permutes the ranges of tables in kl; - safeAdd(p,q,n) : adds x^n.q to p, checking for overflow; - safeSubtract(p,q,mu,h) : subtracts x^h.mu.q from p, checking for underflow; - zeroPol() : returns the zero-polynomial; ****************************************************************************/ namespace { void allocExtrRow(KLContext& kl, ExtrRow& row, const CoxNbr& y) /* This function does the allocation of the extremal row for y, but in row instead of in kl.extrList(y). */ { const SchubertContext& p = kl.schubert(); BitMap b(kl.size()); p.extractClosure(b,y); if (ERRNO) return; maximize(p,b,p.descent(y)); readBitMap(row,b); if (ERRNO) return; return; } void appendStar(String& str, const KLContext& kl, const CoxNbr& x, const KLPol& pol, const Length& l) /* Appends a star to the string if mu != 0. */ { if (l != undef_length) { const SchubertContext& p = kl.schubert(); Length l_x = p.length(x); if (2*pol.deg()+1+l_x == l) io::append(str," *"); } return; } MuData* find(MuRow& row, const CoxNbr& x) /* Finds x in the row and returns the address of the corresponding row. Returns zero if x is not found. Uses binary search. */ { Ulong j0 = (Ulong)(-1); for (Ulong j1 = row.size(); j1-j0 > 1;) { Ulong j = j0 + (j1-j0)/2; if (row[j].x == x) // m was found return row.ptr()+j; if (row[j].x < x) j0 = j; else j1 = j; } return 0; } }; namespace kl { const KLPol& one() { static KLPol p(1,KLPol::const_tag()); return p; } }; namespace { void printStar(FILE* file, const KLContext& kl, const CoxNbr& x, const KLPol& pol, const Length& l) /* Like appendStar, but with output to a file. */ { if (l != undef_length) { const SchubertContext& p = kl.schubert(); Length l_x = p.length(x); if (2*pol.deg()+1+l_x == l) fprintf(file," *"); } return; } KLPol& safeAdd(KLPol& p, const KLPol& q, const Degree& n) /* This function increments p by q, shifted by x^n, checking for overflow. It is assumed that the result fits in p. Forwards the error KLCOEFF_OVERFLOW in case of error. */ { if (p.deg() < (q.deg()+n)) p.setDeg(q.deg() + n); for (Degree j = 0; j <= q.deg(); ++j) { klsupport::safeAdd(p[j+n],q[j]); if (ERRNO) return p; } return p; } KLPol& safeSubtract(KLPol& p, const KLPol& q, const KLCoeff& mu, const Length& h) /* This function subtracts mu times q shifted by x^h from p, checking for underflow. Sets the error KLCOEFF_NEGATIVE in case of problem. */ { for (Degree j = 0; j <= q.deg(); ++j) { KLCoeff a = mu; safeMultiply(a,q[j]); if (ERRNO) { /* overflow; this will cause an underflow */ ERRNO = KLCOEFF_NEGATIVE; return p; } klsupport::safeSubtract(p[j+h],a); if (ERRNO) return p; } p.reduceDeg(); return p; } KLPol& zeroPol() /* Returns the zero polynomial (usually this indicates an error condition.) */ { static KLPol z(undef_degree); return z; } }; positivity_final/klsupport.cpp0000600000175000017500000003135010011171251020370 0ustar duclouxducloux00000000000000/* This is klsupport.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "klsupport.h" /* This module contains code for the operations that can be "factored out" amongst the various k-l tables : the ordinary one, the inverse one, and the one with unequal parameters. Foremost, this is the extremal list. In all these cases, k-l polynomials can be readily reduced to the case of "extremal pairs". */ /***************************************************************************** Chapter I -- The KLSupport class. This class can be seen as an extension of the schubert context, oriented towards k-l computations. Its main function is to construct and maintain extrList. Recall that this is a list of rows of CoxNbr. The row for y is never allocated if inverse[y] < y (this becomes a bit cumbersome, and I'm really tempted to drop it! the main reason for keeping it is that it really speeds up and reduces the computations by pushing y down faster, by an important factor (at least two in my trials.)) If the row is allocated, then it always contains the full list of extremal pairs for y, i.e. those x <= y for which LR(x) contains LR(y). The other stuff is trivial : inverse is the (partially defined) table of inverses, last is the last term in the internal normal form (also kept because it provides a better descent strategy), involution flags the involutions in the context. The interface field is here because it was in KLContext, but it should probably go away, and be present as a parameter in the functions that need it. The idea in this program is that schubert is really an auxiliary to klsupport; the updating of schubert should go only through klsupport, and the two will always be kept consistent. The following functions are provided : - constructors and destructors : - KLSupport(SchubertContext*, const Interface*); - ~KLSupport(); - accessors : - inverseMin(const CoxNbr& x) : returns min(x,x_inverse); - standardPath(List& g, const CoxNbr& x) : returns in g the standard descent path from x - manipulators : - applyInverse(const CoxNbr& y) : writes the row from inverse in y; - applyIPermutation(const CoxNbr& y, const Permutation& a) : applies the (inverse) permutation to extrList(y); (inlined) - extendContext(const CoxWord& g) : extends the context to hold g; - permute(const Permutation& a) : applies the permutation to the data; - revertSize(const Ulong& n) : reverts to previous size after a failed extension; *****************************************************************************/ namespace klsupport { KLSupport::KLSupport(SchubertContext* p) :d_schubert(p), d_extrList(1), d_inverse(1), d_last(1), d_involution(1) { /* make first row of d_extrList, for the identity element */ d_extrList[0] = new ExtrRow(1); d_extrList.setSizeValue(1); ExtrRow& e = *d_extrList[0]; e.setSizeValue(1); d_inverse.setSizeValue(1); d_last.setSizeValue(1); d_last[0] = undef_generator; d_involution.setBit(0); } KLSupport::~KLSupport() /* Delete the pointers that were allocated by klsupport. */ { for (Ulong j = 0; j < d_extrList.size(); ++j) { delete d_extrList[j]; } delete d_schubert; return; } /******** accessors *********************************************************/ CoxNbr KLSupport::inverseMin(const CoxNbr& x) const /* Returns the minimum of x and x_inverse. */ { if (x <= inverse(x)) return x; else return inverse(x); } void KLSupport::standardPath(List& g, const CoxNbr& x) const { const SchubertContext& p = schubert(); /* find sequence of shifts */ Length j = p.length(x); g.setSize(j); CoxNbr x1 = x; while (j) { --j; if (inverse(x1) < x1) { /* left shift */ Generator s = last(inverse(x1)); g[j] = s + rank(); x1 = p.lshift(x1,s); } else { Generator s = last(x1); g[j] = last(x1); x1 = p.rshift(x1,s); } } return; } /******** manipulators ******************************************************/ void KLSupport::allocExtrRow(const CoxNbr& y) /* Allocates one row in d_extrList. The row contains the list of elements x <= y s.t. LR(y) is contained in LR(x), i.e., which cannot be taken further up by the application of a generator in LR(y). Forwards the error MEMORY_WARNING if CATCH_MEMORY_ERROR is set. */ { const SchubertContext& p = schubert(); BitMap b(size()); p.extractClosure(b,y); if (ERRNO) return; maximize(p,b,p.descent(y)); d_extrList[y] = new ExtrRow(b.begin(),b.end()); /* an error may be set here */ return; } void KLSupport::allocRowComputation(const CoxNbr& y) /* This function makes sure that all the extremal rows in the standard descent path from y are allocated. The idea is that all these rows will come up when the full row for y is computed, so one might as well fill them anyway; doing them all at the same time will save many Bruhat closure computations, which are relatively expensive. Still, this function looks like overkill to me. I'm leaving it in because it is working and it was a pain to write! Things wouldn't be so bad if there wasn't also the passage to inverses! */ { static List e(0); const SchubertContext& p = schubert(); /* find sequence of shifts */ standardPath(e,y); SubSet q(size()); q.reset(); q.add(0); if (ERRNO) goto abort; { CoxNbr y1 = 0; for (Ulong j = 0; j < e.size(); ++j) { Generator s = e[j]; p.extendSubSet(q,s); /* extend the subset */ if (ERRNO) goto abort; y1 = p.shift(y1,s); CoxNbr y2 = inverseMin(y1); if (!isExtrAllocated(y2)) { /* allocate row */ /* copy bitmap of subset to buffer */ BitMap b = q.bitMap(); if (ERRNO) goto abort; /* extremalize */ maximize(p,b,p.descent(y1)); d_extrList[y1] = new ExtrRow(b.begin(),b.end()); /* go over to inverses if necessary */ if (s >= rank()) { applyInverse(y2); d_extrList[y2]->sort(); } } } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLSupport::applyInverse(const CoxNbr& y) /* This function puts in d_extrList[y] the row of inverses of d_extrList[yi], where yi is the inverse of y, and sets the row of yi to zero. The row is not sorted (this can be done with sortIRow). */ { CoxNbr yi = inverse(y); d_extrList[y] = d_extrList[yi]; d_extrList[yi] = 0; ExtrRow& e = *d_extrList[y]; for (Ulong j = 0; j < e.size(); ++j) { e[j] = inverse(e[j]); } return; } CoxNbr KLSupport::extendContext(const CoxWord& g) /* Extends the context to accomodate g. The return value is the context number of g in case of success, and undef_coxnbr in case of failure. Forwards the error EXTENSION_FAIL in case of error. */ { CoxNbr prev_size = size(); SchubertContext& p = *d_schubert; CoxNbr x = p.extendContext(g); if (ERRNO) /* ERRNO is EXTENSION_FAIL */ return undef_coxnbr; CATCH_MEMORY_OVERFLOW = true; d_extrList.setSize(size()); if (ERRNO) goto revert; d_inverse.setSize(size()); if (ERRNO) goto revert; d_last.setSize(size()); if (ERRNO) goto revert; d_involution.setSize(size()); if (ERRNO) goto revert; CATCH_MEMORY_OVERFLOW = false; /* extend the list of inverses */ for (CoxNbr x = 0; x < prev_size; ++x) { if (inverse(x) == undef_coxnbr) { /* try to extend */ Generator s = p.firstRDescent(x); CoxNbr xs = p.rshift(x,s); if (inverse(xs) == undef_coxnbr) d_inverse[x] = undef_coxnbr; else d_inverse[x] = p.lshift(inverse(xs),s); } } for (CoxNbr x = prev_size; x < size(); ++x) { Generator s = p.firstRDescent(x); CoxNbr xs = p.rshift(x,s); if (inverse(xs) == undef_coxnbr) d_inverse[x] = undef_coxnbr; else d_inverse[x] = p.lshift(inverse(xs),s); } for (CoxNbr x = prev_size; x < size(); ++x) { if (inverse(x) == x) d_involution.setBit(x); } /* extend list of last elements */ for (CoxNbr x = prev_size; x < size(); ++x) { Generator s = p.firstLDescent(x); CoxNbr sx = p.lshift(x,s); if (sx) d_last[x] = d_last[sx]; else /* x = s */ d_last[x] = s; } return x; revert: CATCH_MEMORY_OVERFLOW = false; revertSize(prev_size); return undef_coxnbr; } void KLSupport::permute(const Permutation& a) /* Applies the permutation a to the data in the context. The meaning of a is that it takes element number x in the context to element number a(x). The procedure is explained in full in kl.h. */ { /* permute schubert context */ d_schubert->permute(a); /* permute values */ for (CoxNbr y = 0; y < size(); ++y) { if (d_extrList[y] == 0) continue; ExtrRow& e = *d_extrList[y]; for (Ulong j = 0; j < e.size(); ++j) { e[j] = a[e[j]]; } } for (CoxNbr y = 0; y < size(); ++y) { if (inverse(y) != undef_coxnbr) d_inverse[y] = a[inverse(y)]; } /* permute ranges */ BitMap b(a.size()); for (CoxNbr x = 0; x < size(); ++x) { if (b.getBit(x)) continue; if (a[x] == x) { b.setBit(x); continue; } for (CoxNbr y = a[x]; y != x; y = a[y]) { /* back up values for y */ ExtrRow* extr_buf = d_extrList[y]; CoxNbr inverse_buf = inverse(y); Generator last_buf = last(y); bool involution_buf = isInvolution(y); /* put values for x in y */ d_extrList[y] = d_extrList[x]; d_inverse[y] = inverse(x); d_last[y] = last(x); if (isInvolution(x)) d_involution.setBit(y); else d_involution.clearBit(y); /* store backup values in x */ d_extrList[x] = extr_buf; d_inverse[x] = inverse_buf; d_last[x] = last_buf; if (involution_buf) d_involution.setBit(x); else d_involution.clearBit(x); /* set bit*/ b.setBit(y); } b.setBit(x); } return; } void KLSupport::revertSize(const Ulong& n) /* This function reverts the size of the context to a previous value n. Note that the allocated sizes of the lists are not changed; we simply preserve the consistency of the various size values. */ { d_schubert->revertSize(n); d_extrList.setSize(n); d_inverse.setSize(n); d_last.setSize(n); return; } }; /***************************************************************************** Chapter II -- Utilities. This section defines some utility functions declared in klsupport.h : - safeAdd(const KLCoeff&, const KLCoeff&) : safe addition; - safeAdd(SKLCoeff&, const SKLCoeff&) : safe addition; *****************************************************************************/ namespace klsupport { KLCoeff& safeAdd(KLCoeff& a, const KLCoeff& b) /* This function increments a with b, if the result does not exceed KLCOEFF_MAX; otherwise it sets the error KLCOEFF_OVERFLOW and leaves a unchanged. */ { if (b <= KLCOEFF_MAX - a) a += b; else ERRNO = KLCOEFF_OVERFLOW; return a; } SKLCoeff& safeAdd(SKLCoeff& a, const SKLCoeff& b) /* This function increments a with b if the result lies in the interval [SKLCOEFF_MIN,SKLCOEFF_MAX]; sets the error SKLCOEFF_OVERFLOW if we exceed SKLCOEFF_MAX, and SKLCOEFF_UNDERFLOW if we are less than SKLCOEFF_MIN. Note that overflow can occur only if b is positive, underflow only if b is negative. */ { if ((b > 0) && (a > SKLCOEFF_MAX - b)) { ERRNO = SKLCOEFF_OVERFLOW; } else if ((b < 0) && (a < SKLCOEFF_MIN - b)) { ERRNO = SKLCOEFF_UNDERFLOW; } else a += b; return a; } KLCoeff& safeMultiply(KLCoeff& a, const KLCoeff& b) /* This function multiplies a with b, if the result does not exceed KLCOEFF_MAX; otherwise it sets the error KLCOEFF_OVERFLOW and leaves a unchanged. */ { if (a == 0) return a; if (b <= KLCOEFF_MAX/a) a *= b; else ERRNO = KLCOEFF_OVERFLOW; return a; } SKLCoeff& safeMultiply(SKLCoeff& a, const SKLCoeff& b) /* This function multiplies a with b, if the result lies between SKLCOEFF_MIN and SKLCOEFF_MAX. Otherwise it sets the error SKLCOEFF_UNDERFLOW or SKLCOEFF_OVERFLOW as appropriate. */ { if (a == 0) return a; if (a > 0) { if (b > SKLCOEFF_MAX/a) ERRNO = SKLCOEFF_OVERFLOW; else if (b < SKLCOEFF_MIN/a) ERRNO = SKLCOEFF_UNDERFLOW; else a *= b; } else { if (b > SKLCOEFF_MIN/a) ERRNO = SKLCOEFF_UNDERFLOW; else if (b < SKLCOEFF_MAX/a) ERRNO = SKLCOEFF_OVERFLOW; else a *= b; } return a; } KLCoeff& safeSubtract(KLCoeff& a, const KLCoeff& b) /* This function subtracts b from a, if the result is non-negative; sets the error KLCOEFF_UNDERFLOW otherwise, and leaves a unchanged. */ { if (b <= a) a -= b; else ERRNO = KLCOEFF_UNDERFLOW; return a; } }; positivity_final/klsupport.h0000600000175000017500000001112710011171251020035 0ustar duclouxducloux00000000000000/* This is klsupport.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef KLSUPPORT_H /* guard against multiple inclusions */ #define KLSUPPORT_H #include "globals.h" #include "coxtypes.h" #include "list.h" #include "polynomials.h" namespace klsupport { using namespace globals; using namespace coxtypes; using namespace list; using namespace polynomials; }; /******** type declarations **************************************************/ namespace klsupport { class KLSupport; typedef unsigned short KLCoeff; typedef short SKLCoeff; typedef List ExtrRow; }; /******** constants **********************************************************/ namespace klsupport { enum PolynomialType {KLPOL, UNEQ_KLPOL, INV_KLPOL, NUM_POLTYPES}; const KLCoeff KLCOEFF_MAX = USHRT_MAX-1; /* top value is reserved */ const KLCoeff undef_klcoeff = KLCOEFF_MAX + 1; const KLCoeff KLCOEFF_MIN = 0; const SKLCoeff SKLCOEFF_MIN = SHRT_MIN+1; const SKLCoeff SKLCOEFF_MAX = -SKLCOEFF_MIN; const SKLCoeff undef_sklcoeff = SKLCOEFF_MIN-1; }; /******** function declarations **********************************************/ namespace klsupport { KLCoeff& safeAdd(KLCoeff& a, const KLCoeff& b); SKLCoeff& safeAdd(SKLCoeff& a, const SKLCoeff& b); KLCoeff& safeMultiply(KLCoeff& a, const KLCoeff& b); SKLCoeff& safeMultiply(SKLCoeff& a, const SKLCoeff& b); KLCoeff& safeSubtract(KLCoeff& a, const KLCoeff& b); }; /******** type definitions ***************************************************/ #include "schubert.h" namespace klsupport { using namespace schubert; }; namespace klsupport { class KLSupport { private: SchubertContext* d_schubert; List d_extrList; List d_inverse; List d_last; BitMap d_involution; public: List& extrList() {return d_extrList;} // this should go /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLSupport));} KLSupport(SchubertContext* p); ~KLSupport(); /* accessors */ const ExtrRow& extrList(const CoxNbr& y) const; /* inlined */ CoxNbr inverse(const CoxNbr& x) const; /* inlined */ CoxNbr inverseMin(const CoxNbr& x) const; const BitMap& involution() const; /* inlined */ bool isExtrAllocated(const CoxNbr& x) const; /* inlined */ bool isInvolution(const CoxNbr& x) const; /* inlined */ Generator last(const CoxNbr& x) const; /* inlined */ Length length(const CoxNbr& x) const; /* inlined */ Rank rank() const; /* inlined */ const SchubertContext& schubert() const; /* inlined */ CoxNbr size() const; /* inlined */ void sortIRow(const CoxNbr& y, Permutation& a) const; /* inlined */ void standardPath(List& g, const CoxNbr& x) const; /* manipulators */ void allocExtrRow(const CoxNbr& y); void allocRowComputation(const CoxNbr& y); void applyInverse(const CoxNbr& y); void applyIPermutation(const CoxNbr& y, const Permutation& a); /* inlined */ CoxNbr extendContext(const CoxWord& g); void permute(const Permutation& a); void revertSize(const Ulong& n); SchubertContext& schubert(); /* inlined */ }; }; /******** inlined definitions ************************************************/ namespace klsupport { inline const ExtrRow& KLSupport::extrList(const CoxNbr& y) const {return *d_extrList[y];} inline CoxNbr KLSupport::inverse(const CoxNbr& x) const {return d_inverse[x];} inline const BitMap& KLSupport::involution() const {return d_involution;} inline bool KLSupport::isExtrAllocated(const CoxNbr& x) const {return d_extrList[x] != 0;} inline bool KLSupport::isInvolution(const CoxNbr& x) const {return d_involution.getBit(x);} inline Generator KLSupport::last(const CoxNbr& x) const {return d_last[x];} inline Length KLSupport::length(const CoxNbr& x) const {return d_schubert->length(x);} inline Rank KLSupport::rank() const {return d_schubert->rank();} inline CoxNbr KLSupport::size() const {return schubert().size();} inline SchubertContext& KLSupport::schubert() {return *d_schubert;} inline void KLSupport::applyIPermutation(const CoxNbr& y, const Permutation& a) {rightRangePermute(*d_extrList[y],a);} inline const SchubertContext& KLSupport::schubert() const {return *d_schubert;} }; #endif positivity_final/list.h0000600000175000017500000001217310012712102016744 0ustar duclouxducloux00000000000000/* This is list.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef LIST_H /* guarantee single inclusion */ #define LIST_H #include "globals.h" #include namespace list { using namespace globals; }; /******** type declarations *************************************************/ namespace list { template class List; }; /******** constants *********************************************************/ namespace list { const Ulong undef_size = ULONG_MAX; const Ulong not_found = ULONG_MAX; } /******** functions provided by list.h **************************************/ namespace list { template Ulong find(const List& l, const T& m); template Ulong insert(List& l, const T& m); template void print(FILE* file, const List& l); }; /******** type definitions **************************************************/ #include "memory.h" namespace list { using namespace memory; }; namespace list { template class List { protected: T* d_ptr; Ulong d_size; Ulong d_allocated; public: typedef T eltType; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(List));} void* operator new(size_t, void* ptr) {return ptr;} void operator delete(void* ptr, void* placement) {}; List() {memset(this,0,sizeof(List));} // guarantee clean memory List(const Ulong& n); List(const List& r); List(const T* p, const Ulong& n); template List(const I& first, const I& last); template List(const I& first, const I& last, F& f); ~List(); /* modifiers */ T& operator[] (Ulong j); /* inlined */ const List& operator= (const List& r); void append(const T& x); const List& assign(const List& r); Ulong& size() {return d_size;} void erase(const Ulong& n); void reverse(); T* ptr() {return d_ptr;} void setData(const T* source, Ulong first, Ulong r); void setData(const T* source, Ulong r); /* inlined */ void setSize(Ulong n); void setSizeValue(const Ulong& n); /* inlined */ void setZero(Ulong first, Ulong r); /* inlined */ void setZero(Ulong r); /* inlined */ void setZero(); /* inlined */ void shallowCopy(const List& w); /* inlined */ void shiftPtr(const long& d); /* inlined */ void sort(); template void sort(C& c); /* inlined */ /* accessors */ const T& operator[] (Ulong j) const; /* inlined */ bool operator== (const List& w) const; bool operator!= (const List& w) const; bool operator< (const List& w) const; T *const& ptr() const; /* inlined */ const Ulong& size() const; /* inlined */ /* iterator */ typedef T* Iterator; typedef const T* ConstIterator; Iterator begin(); /* inlined */ Iterator end(); /* inlined */ ConstIterator begin() const; /* inlined */ ConstIterator end() const; /* inlined */ }; }; /******** Implementation of inline functions *******************************/ namespace list { /* class List */ /* modifiers */ template inline T& List::operator[] (Ulong j) {return d_ptr[j];} template inline void List::setData(const T *const source, Ulong r) {setData(source,0,r);} template void List::setSizeValue(const Ulong& n) {d_size = n;} template inline void List::setZero(Ulong first, Ulong r) {memset(d_ptr+first,0,r*sizeof(T));} template inline void List::setZero(Ulong r) {setZero(0,r);} template inline void List::setZero() {setZero(0,d_size);} template inline void List::shallowCopy(const List& w) {memmove(this,&w,sizeof(List));} template inline void List::shiftPtr(const long& d) {d_ptr += d; d_size -= d; d_allocated -= d;} /* accessors */ template inline const T& List::operator[] (Ulong j) const {return(d_ptr[j]);} template inline bool List::operator!= (const List& w) const {return !operator==(w);} template inline T *const& List::ptr() const {return d_ptr;} template inline const Ulong& List::size() const {return d_size;} /* iterators */ template inline typename List::Iterator List::begin() {return d_ptr;} template inline typename List::Iterator List::end() {return d_ptr+d_size;} template inline typename List::ConstIterator List::begin() const {return d_ptr;} template inline typename List::ConstIterator List::end() const {return d_ptr+d_size;} }; #include "list.hpp" #endif positivity_final/list.hpp0000600000175000017500000002466210012711701017316 0ustar duclouxducloux00000000000000/* This is list.hpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include #include "error.h" namespace list { using namespace error; }; /************************************************************************** This file provides the definitions of the functions for the List and List classes. As far as I can see, List is the basic_string type of the standard library; the reason I didn't use the library class is mostly that I'm not familiar with it; also that I want to keep the code small, but most importantly, I want to keep memory management in my own hands. List is a variant of List where the sizes are fixed. **************************************************************************/ /************************************************************************** Chapter I -- The List class. This section provides the following functions : - constructors and destructors : - List(Ulong); - List(List&); - List(T*,ulong); - List(const I&, const I&); - List(const I&, const I&, F&); - ~List(); - accessors : - operator== (const List&) : tests for equality; - operator< (const List&) : comparison operator; - modifiers : - append(const T&): appends an element (potentially resizing); - assign(const List&): copy constructor; - erase(const Ulong&): erases the n-th term in the list; - reverse(): reverses the order of the elements; - setSize(Ulong): resizes; - setData(T*,first,Ulong): sets the data, resizing if necessary; - sort() : sorts the list; **************************************************************************/ namespace list { template List::List(const Ulong& n) /* Allocates this to hold n elements. Relies on the fact that it always receives clean memory from alloc, and that the default constructor does nothing. */ { d_allocated = arena().allocSize(n,sizeof(T)); d_ptr = (T*)arena().alloc(n*sizeof(T)); d_size = 0; } template List::List(const List& r) /* Copy constructor. Contrary to assignment, constructs fully new objects. */ { d_ptr = (T*)arena().alloc(r.size()*sizeof(T)); d_allocated = arena().allocSize(r.size(),sizeof(T)); for (Ulong j = 0; j < r.size(); ++j) { new(d_ptr+j) T(r[j]); } d_size = r.size(); } template List::List(const T* p, const Ulong& n) :d_allocated(0) /* Constructor for the List class, allocating the list to size n, and initializing it with the first n members pointed by T (recall that our lists are really strings --- bitwise copying is assumed for T) */ { d_ptr = (T*)arena().alloc(n*sizeof(T)); d_allocated = arena().allocSize(n,sizeof(T)); memcpy(d_ptr,p,n*sizeof(T)); d_size = n; } template template List::List(const I& first, const I& last) /* A list constructor taking iterators as parameters. It is assumed that the value-type of I may be allocated to T. */ { memset(this,0,sizeof(List)); for (I i = first; i != last; ++i) { append(*i); } } template template List::List(const I& first, const I& last, F& f) /* Like the previous one, except that in addition F is a functor taking one argument of type I::value_type, and whose value-type may be allocated to T. */ { memset(this,0,sizeof(List)); for (I i = first; i != last; ++i) { append(f(*i)); } } template List::~List() /* Destructor for the List class : releases the memory. NOTE : this has essentially the effect of what delete[] d_ptr would do if I could get it to work. */ { for (Ulong j = 0; j < d_allocated; ++j) { d_ptr[j].~T(); } arena().free(d_ptr,d_allocated*sizeof(T)); } /******** accessors *********************************************************/ template bool List::operator== (const List& w) const /* Equality operator for lists. Two lists are equal if they have the same size, and if the elements in the range [0,size[ are pairwise equal. It assumes that operator== is defined for T. */ { if (d_size != w.size()) return false; for (Ulong j = 0; j < d_size; ++j) { if (!(d_ptr[j] == w[j])) return false; } return true; } template bool List::operator< (const List& w) const /* Comparison operator for lists. Comparison is length-first, lexicographical. It assumes operator< is defined for T. */ { if (d_size < w.size()) return true; if (d_size > w.size()) return false; /* if we reach this point, sizes are equal */ for (Ulong j = 0; j < d_size; ++j) { if (d_ptr[j] < w[j]) return true; if (d_ptr[j] > w[j]) return false; } /* if we reach this point, lists are equal */ return false; } /******** modifiers *********************************************************/ template const List& List::operator= (const List& r) { assign(r); return *this; } template void List::append(const T& x) /* Appends one element to the list, resizing if necessary. Forwards the error MEMORY_WARNING if CATCH_MEMORY_OVERFLOW is set. */ { Ulong c = d_size; setSize(c+1); if (ERRNO) /* overflow */ return; d_ptr[c] = x; return; } template const List& List::assign(const List& r) /* Assigns r to the current list, by a one-level copy (in other words, treats Lists as BasicStrings). Forwards the error MEMORY_WARNING if CATCH_MEMORY_OVERFLOW is set. NOTE : the return value in case of error should rather be 0, but this would mean that the function should really return a pointer. */ { setSize(r.size()); if (ERRNO) /* overflow */ return *this; setData(r.ptr(),r.size()); return *this; } template void List::erase(const Ulong& n) /* This function erases the n-th term in the list, by shifting up. */ { memmove(d_ptr+n,d_ptr+n+1,(d_size-n-1)*sizeof(T)); d_size--; } template void List::reverse() /* Reverses the order of the elements in the list. */ { for (Ulong j = 0; j < d_size/2; ++j) { T a = d_ptr[j]; d_ptr[j] = d_ptr[d_size-j-1]; d_ptr[d_size-j-1] = a; } return; } template void List::setSize(Ulong n) /* Checks if the varlist will hold n nodes of data, and resizes it if not. Forwards the error MEMORY_WARNING if CATCH_MEMORY_ERROR is set. */ { if (d_allocated < n) { /* resize */ void *p = arena().realloc(d_ptr,d_allocated*sizeof(T),n*sizeof(T)); if (ERRNO) /* overflow */ return; d_ptr = (T*)p; // Ulong old_alloc = d_allocated; d_allocated = arena().allocSize(n,sizeof(T)); // the following line causes trouble; I can't understand why! // new(d_ptr+old_alloc) T[d_allocated-old_alloc]; } d_size = n; return; } template void List::setData(const T *source, Ulong first, Ulong r) /* After resizing if necessary, moves the first r entries of source to the list, starting at first. Forwards the error MEMORY_WARNING if CATCH_MEMORY_ERROR is set. */ { if (d_size < first+r) { setSize(first+r); if (ERRNO) /* overflow */ return; } memmove(d_ptr+first,source,r*sizeof(T)); return; } template void List::sort() /* Sorts the list in the natural order of the elements. It is assumed that operator> is defined for T. */ { /* set the starting value of h */ Ulong h = 1; for (; h < d_size/3; h = 3*h+1) ; /* do the sort */ for (; h > 0; h /= 3) { for (Ulong j = h; j < d_size; ++j) { T a = d_ptr[j]; Ulong i = j; for (; (i >= h) && (d_ptr[i-h] > a); i -= h) d_ptr[i] = d_ptr[i-h]; d_ptr[i] = a; } } return; } template template void List::sort(C& c) /* Sorts the list in the order defined by the comparison functor c. It is assumed that c takes two arguments of type T, and that c(x,y) is true if x <= y (so that the relation x > y is expressed by !c(c,y)) */ { /* set the starting value of h */ Ulong h = 1; for (; h < d_size/3; h = 3*h+1) ; /* do the sort */ for (; h > 0; h /= 3) { for (Ulong j = h; j < d_size; ++j) { T a = d_ptr[j]; Ulong i = j; for (; (i >= h) && !c(d_ptr[i-h],a); i -= h) d_ptr[i] = d_ptr[i-h]; d_ptr[i] = a; } } return; } }; /************************************************************************** Chapter III -- Insertion and deletion A list will often be constructed by first catching the elements in a buffer, then copying the buffer onto the final list. For each type of coefficient, we will need an insertion function. We provide an abstract template. **************************************************************************/ namespace list { template Ulong insert(List& l, const T& m) /* Inserts a new element in the (ordered) list, using binary search to find the insertion point. Forwards the error MEMORY_WARNING if CATCH_MEMORY_ERROR is set. Return value is not_found in case of error. NOTE :It is assumed that operator<= is defined for the class T. */ { Ulong j0 = ~0L; Ulong j1 = l.size(); for (; j1-j0 > 1;) { Ulong j = j0 + (j1-j0)/2; if (l[j] == m) /* m was found */ return j; if (l[j] < m) j0 = j; else j1 = j; } /* at this point j1 = j0+1; insertion point is j1 */ l.setSize(l.size()+1); if (ERRNO) /* overflow */ return not_found; l.setData(l.ptr()+j1,j1+1,l.size()-j1-1); /* shift tail up by one */ new(l.ptr()+j1) T(m); return j1; } template Ulong find(const List& l, const T& m) /* Finds the index of m in the list. If m is not found, returns not_found. Uses binary search. */ { Ulong j0 = ~0L; for (Ulong j1 = l.size(); j1-j0 > 1;) { Ulong j = j0 + (j1-j0)/2; if (l[j] == m) /* m was found */ return j; if (l[j] < m) j0 = j; else j1 = j; } return not_found; } }; /************************************************************************** Chapter IV -- Input/output This section defines some i/o functions for lists : - print(file,l) : prints l on the file; **************************************************************************/ namespace list { template void print(FILE* file, const List& l) /* Rudimentary print function for lists. It assumes that print(FILE*,T) is defined. */ { for (Ulong j = 0; j < l.size(); ++j) { print(file,l[j]); if (j+1 < l.size()) /* more to come */ fprintf(file,","); } } }; positivity_final/main.cpp0000600000175000017500000002110410011171251017245 0ustar duclouxducloux00000000000000/* This is main.c Coxeter version 3.0 Copyright (c) 2002 Fokko du Cloux This program is made available under the terms stated in the Gnu General Public License below. Enquiries about the General Public License and the Gnu project may be adressed to : Free Software Foundation 675 Mass. Ave., Cambridge, MA 02139, USA GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS */ #include "constants.h" #include "commands.h" #include "version.h" namespace { using namespace version; void printVersion(); }; int main() /* In this version, the program can only run in interactive mode, and does not take any arguments. */ { constants::initConstants(); printVersion(); commands::run(); exit(0); } namespace { void printVersion() /* Prints an opening message and the version number. */ { printf("This is %s version %s.\nEnter help if you need assistance,\ carriage return to start the program.\n\n",NAME,VERSION); return; } }; positivity_final/memory.cpp0000600000175000017500000001613210035001705017640 0ustar duclouxducloux00000000000000/* This is memory.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "memory.h" #include #include "error.h" namespace memory { using namespace error; }; namespace { using namespace memory; const Ulong MEMORY_MAX = ULONG_MAX; const Ulong ABYTES = sizeof(Align); const Ulong ARENA_BITS = 16; }; /**************************************************************************** This module contains the memory allocator for this program. Since we are doing a lot of dynamic memory allocation, and use many variable-sized structures, both small and large, efficient memory allocation seems to be a crucial performance issue. We try to take an approach which is as simple as possible, for the sake of efficiency, while trying to be not too wasteful. First of all, memory is gotten from the system, via calloc, in chunks of 2^N.a bytes, where a = ABYTES will ensure proper alignment for all the types used in this program (here we make the crucial assumption that all builtin types have a size which is a power of two.) The only exception is when a memory request does not fit in such a chunk; then we allocate a block of size 2^m.a for large enough m. These chunks, once gotten, are never given back; however, we try to reuse them insofar as possible. Only three basic operations are provided : alloc, which returns a pointer to a new memory block; grow, which resizes a block to a larger block; and free, which frees a block. All blocks handed out in this way have sizes of the form 2^m.a, 0 <= m < BITS(Ulong). On average this should lead to a memory efficiency of 75%, which is not worse than what I was doing earlier, anyway. ****************************************************************************/ namespace memory { Arena& arena() { static Arena a(ARENA_BITS); return a; } }; /**************************************************************************** Chapter I -- The Arena class. ****************************************************************************/ namespace memory { Arena::Arena(Ulong bsBits) { memset(d_list,0,BITS(Ulong)*sizeof(void *)); memset(d_used,0,BITS(Ulong)*sizeof(Ulong)); memset(d_allocated,0,BITS(Ulong)*sizeof(Ulong)); d_bsBits = bsBits; d_count = 0; } Arena::~Arena() /* Nothing to do here! All memory is allocated in fixed-size arrays. */ {} void Arena::newBlock(unsigned b) /* Provides a new block of size 2^{b}. It looks first of a block of size > 2^b is available; if yes, it splits the required block up from that one. If not, it requests from the system a block of size 2^d_bsBits, if b <= d_bsBits, and of size 2^b otherwise (the unit here is always ABYTES.) Note that this is the only place where we can run out of memory. In that case, the error OUT_OF_MEMORY is set, and the corresponding error function run. In most cases, this will terminate the program. In case of failure, returns a null pointer. NOTE : as this function will be heavily used, it should be rewritten using a bitmap of available blocks. */ { for (unsigned j = b+1; j < BITS(Ulong); ++j) { if (d_list[j]) /* split this block up */ { Align *ptr = (Align *)d_list[j]; d_list[j] = d_list[j]->next; d_allocated[j]--; for (unsigned i = b; i < j; ++i) { d_list[i] = (MemBlock *)(ptr + (1L<next = (MemBlock *)ptr; d_list[b]->next->next = 0; d_allocated[b]++; return; } } /* if we get here we need more memory from the system */ if (b >= d_bsBits) { /* get block directly */ if (d_count > MEMORY_MAX-(1L< MEMORY_MAX-(1L<next = (MemBlock *)ptr; d_allocated[b]++; return; } void* Arena::alloc(size_t n) /* Returns a pointer to a block of 2^m.ABYTES bytes, where m is the smallest integer such that 2^m.ABYTES >= n. It is assumed that ABYTES is a power of 2. The memory is zero-initialized. */ { if (n == 0) return 0; /* compute size of block */ unsigned b = 0; if (n > ABYTES) b = lastBit(n-1)-lastbit[ABYTES]+1; if (d_list[b] == 0) { /* need to make a new block */ newBlock(b); if (ERRNO) return 0; } /* take block off from list */ MemBlock *block = d_list[b]; d_list[b] = d_list[b]->next; block->next = 0; d_used[b]++; return (void *)block; } Ulong Arena::allocSize(Ulong n, Ulong m) const /* Returns the size of the actual memory allocation provided on a request of n nodes of size m, in units of m */ { if (n == 0) return 0; if (n*m <= ABYTES) return ABYTES/m; return ((1 << lastBit(n*m-1)-lastbit[ABYTES]+1)*ABYTES)/m; } Ulong Arena::byteSize(Ulong n, Ulong m) const /* Returns the actual number of bytes of the memory allocation (as opposed to allocSize, which rounds the allocation to the largest multiple of m.) */ { if (n == 0) return 0; if (n*m <= ABYTES) return ABYTES; return (1 << lastBit(n*m-1)-lastbit[ABYTES]+1)*ABYTES; } void *memory::Arena::realloc(void *ptr, size_t old_size, size_t new_size) /* Resizes ptr to size new_size. This involves getting the larger block, copying the contents of ptr to it, and freeing ptr; we never try to fuse smaller adjacent blocks together. Returns 0 and sets the error MEMORY_WARNING in case of overflow, if CATCH_MEMORY_OVERFLOW is set. NOTE : equivalent to alloc if old_size = 0. */ { void *new_ptr = alloc(new_size); if (ERRNO) /* overflow */ return 0; if (old_size) { memcpy(new_ptr,ptr,old_size); free(ptr,old_size); } return new_ptr; } void Arena::free(void *ptr, size_t n) /* Returns the memory block allocated to ptr to the free list. In order to know to which list the pointer should be appended (it will in fact be prepended), we need to pass the size to which ptr was allocated. */ { if (ptr == 0) return; if (n == 0) return; unsigned b = 0; if (n > ABYTES) b = lastBit(n-1)-lastbit[ABYTES]+1; memset(ptr,0,(1L<next = d_list[b]; d_list[b] = block; d_used[b]--; return; } void Arena::print(FILE *file) const /* Prints information about the memory arena. */ { fprintf(file,"%-10s%10s/%-10s\n","size : 2^","used","allocated"); Ulong used_count = 0; for (unsigned j = 0; j < BITS(Ulong); ++j) { fprintf(file,"%3u%7s%10lu/%-10lu\n",j,"",d_used[j],d_allocated[j]); used_count += (1L<(d_count),ABYTES); } }; positivity_final/memory.h0000600000175000017500000000350510035001425017304 0ustar duclouxducloux00000000000000/* This is memory.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef MEMORY_H /* guard against multiple inclusions */ #define MEMORY_H #include "globals.h" namespace memory { using namespace globals; }; /******** type declarations *************************************************/ namespace memory { union Align; class Arena; class FixArena; }; /******** function declarations *********************************************/ void* operator new (size_t size, memory::Arena& a); void* operator new[] (size_t size, memory::Arena& a); namespace memory { Arena& arena(); }; /******** Type definitions **************************************************/ #include "constants.h" namespace memory { using namespace constants; }; union memory::Align { Ulong d_ulong; void *d_voidptr; }; class memory::FixArena { public: }; class memory::Arena { struct MemBlock { MemBlock *next; }; MemBlock* d_list[sizeof(Ulong)*CHAR_BIT]; Ulong d_used[sizeof(Ulong)*CHAR_BIT]; Ulong d_allocated[sizeof(Ulong)*CHAR_BIT]; unsigned d_bsBits; unsigned d_count; void newBlock(unsigned b); public: /* constructors and destructors */ void operator delete(void* ptr) {arena().free(ptr,sizeof(Arena));} Arena(Ulong bsBits); ~Arena(); /* modifiers */ void *alloc(size_t n); void *realloc(void *ptr, size_t old_size, size_t new_size); void free(void *ptr, size_t n); /* accessors */ Ulong allocSize(Ulong n, Ulong m) const; Ulong byteSize(Ulong n, Ulong m) const; void print(FILE* file) const; }; /******** Inline implementations *****************************************/ inline void* operator new(size_t size, memory::Arena& a) {return a.alloc(size);} inline void* operator new[](size_t size, memory::Arena& a) {return a.alloc(size);} #endif positivity_final/minroots.cpp0000600000175000017500000014761510011171251020213 0ustar duclouxducloux00000000000000/* This is minroots.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "minroots.h" namespace { using namespace minroots; const Ulong dihedral = MINNBR_MAX + 4; const int first_dotval = locked; const int first_negdotval = neg_cos; const int dotval_size = 13; const int dotval_negsize = 4; }; /* auxiliary classes */ namespace { class InitMinTable:public MinTable { public: InitMinTable() {}; InitMinTable(CoxGraph& G); MinNbr dihedralShift(MinNbr r, Generator s, Generator t, Ulong c); void initMinTable(CoxGraph& G); void fillDepthOneRow(CoxGraph& G, MinNbr r, Generator s); void fillDihedralRoots(CoxGraph& G); void fillDihedralRow(CoxGraph& G, MinNbr r, Generator s, Length d); void fillMinTable(CoxGraph& G); void fillReflectionRow(CoxGraph& G, MinNbr r, Generator s); void newDepthOneRoot(CoxGraph& G, MinNbr r, Generator s); void newDepthTwoRoot(CoxGraph& G, MinNbr r, Generator s); void newDihedralRoot(CoxGraph& G, MinNbr r, Generator s, Length d); void newMinRoot(CoxGraph& G, MinNbr r, Generator s); void setMinMemory(unsigned long n) {d_min.setSize(n); d_dot.setSize(n);} inline MinNbr size() {return d_size;} }; DotVal bondCosineSum(CoxEntry m, int a, int b); DotVal *CS3; DotVal *CS4; DotVal *CS5; DotVal *CS6; DotVal *CSm; }; /*************************************************************************** This module implements a construction of the minimal root machine of Brink and Howlett. We refer to Brink and Howlett's paper "A finiteness property and an automatic structure for Coxeter groups", Math. Annalen 296 (1993), pp. 179-190, for a description of the concept of a minimal root (called elementary roots by them), and a proof of their finiteness. See alos Casselman, ... , for a description of how this finite state machine may be used for reduction and normal form checking, and for constructing an automaton recognizing ShortLex. Our main goal is to construct the reflection table, simply as an abstract automaton : the minimal roots are enumerated in some order, depth-first in our case (although this might change if we grow the table on demand; then the only condition will be that the enumeration is compatible with the precedence ordering.) For this, we will keep as additional "control data" for each minimal root a vector containing information about the scalar products with the generators. Let us review some of Brink's results on the structure of minimal roots. First of all, the support supp(r) of a minimal root is always a tree without infinite bonds. Conversely, a connected subset I of S which is a tree without infinite bonds can be the support of a minimal root if and only if there are no multiple bonds contained in-between to other mutliple bonds (notice that two edges in a tree always define a well- defined interval between them, viz. the geodesic between x and y for x in the first bond, y in the second, eliminating any bond-points that it may contain.) Let now I be an admissible support, as above. Then if I has more than one bond, each bond has an interior and an exterior point w.r.t. the other bonds. All interior points belong to the same connected component in the complement of the set of exterior points; I call this the interior component. The connected components of the complement of the interior component are in 1-1 correspondence with the exterior points in the bonds. So each of these components has a well-defined cyclotomy attached to it. In this case, it turns out that there is a unique minimal root with support I and all coefficients < 2; it has coefficient 1 on all interior points, and coefficient c_m on all point of an exterior component of cyclotomy m, where c_m = 2 cos(pi/m). This "basic root" r_I precedes all minimal roots with support I. If there is only one bond in I, with cyclotomy m, then there are two possible "orientations", i.e., the choice of interior and exterior is arbitrary; accordingly we have to basic roots r_I,x and r_I,y, where x and y are the two points in the bond, and r_I,x is the root where x is interior, say. If the cyclotomy is not five, these are again the only roots with all coefficients < 2, and the minimal roots with support I get partitioned into two classes, the ones preceded by r_I,x being the ones where x comes before y in the "history" of the root, and those preceded by r_I,y the other way around. Finally, if there is only one bond with cyclotomy five, there is one further possibility, when the root is preceded by c.e_x + c.e_y, the longest root in the dihedral group . This is both preceded by e_x + c.e_y and c.e_x + e_y. This leads to roots which have only exterior points. .... something is missing here .... So in all cases where there is no cyclotomy five, it turns out that all minimal roots with support I have coefficients which are either integers (on the interior) or integral multiples of c_m (on the exterior component of cyclotomy m). And a close examination of what happens on bond points will show that in all cases scalar products of non-simple roots with simple roots only take values 0, +-(1/2), <= -1 for interior points, 0, =-c_m/2, <= -1 for exterior points. What we do is to allow eleven formal values for scalar products : - 1 (denoted one) : can happen only if v is simple; - <= -1 (denoted locked); - +- 1/2 (denoted half and neg_half); - +- cos(pi/m) (denoted cos, neg_cos) : here cos should be interpreted as "a number in [sqrt(2)/2,1[" - +- (sqrt(5)-1)/4 (denoted hinvgold, neg_hinvgold), only when m = 5; - +- cos(2 pi/m), (denoted cos2, neg_cos2), only when m > 6, where cos2 should be interpreted as "a number in ]1/2,cos[" - +- cos(k pi/m) (denoted undef_posdot, undef_negdot), only when m > 6, and only when the root is dihedral, where undef_posdot should be interpreted as "a number in ]0,cos2[", and undef_negdot as "a number in ]neg_cos2,0["; For each minimal root v, we keep a vector of formal scalar products for v. It is clear how they should be initialized : for v = e_s, we have = 1 if t = s, = 0 is t is not in star(s), and = -c(s,t)/2 otherwise, which is neg_half if m(s,t) = 3, neg_cos otherwise (here c(s,t) = 2 cos(pi/m(s,t))). If we go from v to s.v, we will have = - and = + c(s,t) if s != t We will always assume in the sequel that is not already locked. Then we need to do a formal evalution of the above. Now if t is in the support of the root, and if we agree to treat interior points in all cases as if they had cyclotomy five, then the results of Brink alluded to above show that in all cases the above computation can be done within the cyclotomy of s, i.e., we may compute : + 2.cos. in the cyclotomy m(s,t) if m(s,t) > 3 and + otherwise. Since this has to be of the form cos(k pi/m) in the corresponding cyclotomy, for all cases of cyclotomy <= 6 we have all possible values at our disposal, and moreover 1 and c are independent if m > 3, so either we find one of our values, or we are in a situation which cannot actually arise (in which case we return an undefined value). If t is not in the support, let us first look at the case where s appears for the first time. Then <= -1/2, and if < 0, <= -1/2. So, in all cases the formal intrpretation of cos putting everything in the same cyclotomy will give the correct result, viz. locked. Now if = 0, then if m(s,t) = 3, we will get the correct result = ; if m(s,t) > 3, then if = -1/2 we again get the correct result, neg_cos; and if = neg_cos, we will get the correct result, locked, under the assumption which is true in all cyclotomies that 2 cos.cos >= 1 (i.e., this property is reflected in all cosine sum tables). So already t is locked at zero at the first occurrence of s, unless either m(s,t) = 3, or the coefficient of s is one at the first occurrence. Now look at a possible second occurrence of s, with t still not in the support. Then the only possible value for which is not <= -1/2 is neg_hinvgold which is in any case < -sqrt(2)/2; so we have enough information to lock t in that case also, even computing within the cyclotomy of c(s,t). ***************************************************************************/ /**************************************************************************** Chapter 0 -- Initialization. This section defines the class InitStaticConstants, which is used in the initialization process of MinTable. ****************************************************************************/ namespace { class InitStaticConstants /* for initialization only! */ { public: InitStaticConstants(); }; InitStaticConstants::InitStaticConstants() /* Initializes the following constants used in minroots.cpp : - CS3 : matrix giving a + b, -1 < b < 0 - CS4 : matrix giving a + cos.b, -1 < b < 0, assuming m = 4 (i.e., cos.cos = 1/2); - CS5 : matrix giving a + cos.b, -1 < b < 0, assuming m = 5 (i.e., cos = hinvgold + 1/2); - CS6 : matrix giving a + cos.b, -1 < b < 0, assuming m = 6 (i.e., cos.cos = 3/4); - CSm : matrix giving the sums of cosine values for bonds of valency m >= 7; */ { CS3 = (DotVal *)memory::arena().alloc((dotval_negsize+1)*dotval_size* sizeof(DotVal)); CS4 = (DotVal *)memory::arena().alloc(dotval_negsize*dotval_size* sizeof(DotVal)); CS5 = (DotVal *)memory::arena().alloc(dotval_negsize*dotval_size* sizeof(DotVal)); CS6 = (DotVal *)memory::arena().alloc(dotval_negsize*dotval_size* sizeof(DotVal)); CSm = (DotVal *)memory::arena().alloc((dotval_negsize+1)*dotval_size* sizeof(DotVal)); CS3 += dotval_size; CSm += dotval_size; CS3[-13] = locked; /* locked - cos(*) */ CS3[-12] = undef_dotval; /* undef_negdot - cos(*) : can't occur */ CS3[-11] = locked; /* - cos - cos(*) */ CS3[-10] = undef_dotval; /* - cos2 - cos(*) : can't occur */ CS3[-9] = undef_dotval; /* - half - cos(*) : can't occur */ CS3[-8] = undef_dotval; /* - hinvgold - cos(*) : can't occur */ CS3[-7] = undef_dotval; /* zero - cos(*) : can't occur */ CS3[-6] = undef_dotval; /* hinvgold - cos(*) : can't occur */ CS3[-5] = neg_hinvgold; /* half - cos(*) : can't occur */ CS3[-4] = undef_dotval; /* cos2 - cos(*) : can't occur */ CS3[-3] = undef_dotval; /* cos - cos(*) : can't occur */ CS3[-2] = undef_dotval; /* undef_posdot - cos(*) : can't occur */ CS3[-1] = undef_dotval; /* one - cos(*) : can't occur */ CS3[0] = locked; /* locked - cos */ CS3[1] = locked; /* undef_negdot - cos */ CS3[2] = locked; /* - cos - cos */ CS3[3] = locked; /* - cos2 - cos */ CS3[4] = locked; /* - half - cos */ CS3[5] = locked; /* - hinvgold - cos */ CS3[6] = neg_cos; /* zero - cos */ CS3[7] = neg_half; /* hinvgold - cos in cyclotomy 5 */ CS3[8] = neg_hinvgold; /* half - cos in cyclotomy 5 */ CS3[9] = undef_dotval; /* cos2 - cos : can't occur */ CS3[10] = zero; /* cos - cos */ CS3[11] = undef_dotval; /* undef_posdot - cos : can't occur */ CS3[12] = undef_dotval; /* one - cos : can't occur */ CS3[13] = locked; /* locked - cos2 */ CS3[14] = undef_dotval; /* undef_negdot - cos2 : can't occur */ CS3[15] = locked; /* - cos - cos2 */ CS3[16] = locked; /* - cos2 - cos2 */ CS3[17] = locked; /* - half - cos2 */ CS3[18] = undef_dotval; /* - hinvgold - cos2 : can't occur */ CS3[19] = neg_cos2; /* zero - cos2 */ CS3[20] = undef_dotval; /* hinvgold - cos2 : can't occur */ CS3[21] = undef_dotval; /* half - cos2 : can't occur */ CS3[22] = zero; /* cos2 - cos2 */ CS3[23] = undef_dotval; /* cos - cos2 : can't occur*/ CS3[24] = undef_dotval; /* undef_posdot - cos2 : can't occur */ CS3[25] = undef_dotval; /* one - cos2 : can't occur */ CS3[26] = locked; /* locked - half */ CS3[27] = undef_dotval; /* undef_negdot - half : can't occur */ CS3[28] = locked; /* - cos - half */ CS3[29] = locked; /* - cos2 - half */ CS3[30] = locked; /* - half - half */ CS3[31] = neg_cos; /* - hinvgold - half in cyclotomy 5 */ CS3[32] = neg_half; /* zero - half */ CS3[33] = undef_dotval; /* hinvgold - half : can't occur */ CS3[34] = zero; /* half - half */ CS3[35] = undef_dotval; /* cos2 - half : can't occur */ CS3[36] = hinvgold; /* cos - half in cyclotomy 5 */ CS3[37] = undef_dotval; /* undef_posdot - half : can't occur */ CS3[38] = half; /* one - half */ CS3[39] = locked; /* locked - hinvgold */ CS3[40] = undef_dotval; /* undef_negdot - hinvgold : can't occur */ CS3[41] = locked; /* - cos - hinvgold */ CS3[42] = locked; /* - cos2 - hinvgold : can't occur */ CS3[43] = neg_cos; /* - half - hinvgold in cyclotomy 5 */ CS3[44] = undef_dotval; /* - hinvgold - hinvgold : can't occur */ CS3[45] = neg_hinvgold; /* zero - hinvgold */ CS3[46] = zero; /* hinvgold - hinvgold */ CS3[47] = undef_dotval; /* half - hinvgold : can't occur */ CS3[48] = undef_dotval; /* cos2 - hinvgold : can't occur */ CS3[49] = half; /* cos - hinvgold in cyclotomy 5 */ CS3[50] = undef_dotval; /* undef_posdot - hinvgold : can't occur */ CS3[51] = undef_dotval; /* one - hinvgold : can't occur */ /* the matrix CS4 gives a + 2 cos.b, for b < 0, assuming cyclotomy 4, i.e., cos^2 = 1/2 */ CS4[0] = locked; /* locked - sqrt(2).cos */ CS4[1] = undef_dotval; /* undef_negdot - sqrt(2).cos : can't occur */ CS4[2] = locked; /* - cos - sqrt(2).cos */ CS4[3] = locked; /* - cos2 - sqrt(2).cos */ CS4[4] = locked; /* - half - sqrt(2).cos */ CS4[5] = locked; /* - hinvgold - sqrt(2).cos */ CS4[6] = locked; /* zero - sqrt(2).cos */ CS4[7] = undef_dotval; /* hinvgold - sqrt(2).cos : can't occur */ CS4[8] = neg_half; /* half - sqrt(2).cos */ CS4[9] = undef_dotval; /* cos2 - sqrt(2).cos : can't occur */ CS4[10] = undef_dotval; /* cos - sqrt(2).cos : can't occur */ CS4[11] = undef_dotval; /* undef_posdot - sqrt(2).cos : can't occur */ CS4[12] = zero; /* one - sqrt(2).cos */ CS4[13] = locked; /* locked - sqrt(2).cos2 */ CS4[14] = undef_dotval; /* undef_negdot - sqrt(2).cos2 : can't occur */ CS4[15] = locked; /* - cos - sqrt(2).cos2 */ CS4[16] = locked; /* - cos2 - sqrt(2).cos2 : can't occur */ CS4[17] = locked; /* - half - sqrt(2).cos2 */ CS4[18] = locked; /* - hinvgold - sqrt(2).cos2 : can't occur */ CS4[19] = locked; /* zero - sqrt(2).cos2 */ CS4[20] = undef_dotval; /* hinvgold - sqrt(2).cos2 : can't occur */ CS4[21] = undef_dotval; /* half - sqrt(2).cos2 : can't occur */ CS4[22] = undef_dotval; /* cos2 - sqrt(2).cos2 : can't occur */ CS4[23] = undef_dotval; /* cos - sqrt(2).cos2 : can't occur */ CS4[24] = undef_dotval; /* undef_posdot - sqrt(2).cos2 : can't occur */ CS4[25] = undef_dotval; /* one - sqrt(2).cos2 : can't occur */ CS4[26] = locked; /* locked - sqrt(2).half */ CS4[27] = undef_dotval; /* undef_negdot - sqrt(2).half : can't occur */ CS4[28] = locked; /* - cos - sqrt(2).half */ CS4[29] = locked; /* - cos2 - sqrt(2).half */ CS4[30] = locked; /* - half - sqrt(2).half */ CS4[31] = undef_dotval; /* - hinvgold - sqrt(2).half : can't occur */ CS4[32] = neg_cos; /* zero - sqrt(2).half */ CS4[33] = undef_dotval; /* hinvgold - sqrt(2).half : can't occur */ CS4[34] = undef_dotval; /* half - sqrt(2).half : can't occur */ CS4[35] = undef_dotval; /* cos2 - sqrt(2).half : can't occur */ CS4[36] = zero; /* cos - sqrt(2).half */ CS4[37] = undef_dotval; /* undef_posdot - sqrt(2).half : can't occur */ CS4[38] = undef_dotval; /* one - sqrt(2).half : can't occur */ CS4[39] = locked; /* locked - sqrt(2).hinvgold */ CS4[40] = undef_dotval; /* undef_negdot - sqrt(2).hinvgold : can't occur */ CS4[41] = locked; /* - cos - sqrt(2).hinvgold */ CS4[42] = locked; /* - cos2 - sqrt(2).hinvgold : can't occur */ CS4[43] = neg_cos; /* - half - sqrt(2).hinvgold in cyclotomy 5 */ CS4[44] = undef_dotval; /* - hinvgold - sqrt(2).hinvgold : can't occur */ CS4[45] = neg_hinvgold; /* zero - sqrt(2).hinvgold */ CS4[46] = zero; /* hinvgold - sqrt(2).hinvgold */ CS4[47] = undef_dotval; /* half - sqrt(2).hinvgold : can't occur */ CS4[48] = undef_dotval; /* cos2 - sqrt(2).hinvgold : can't occur */ CS4[49] = half; /* cos - sqrt(2).hinvgold in cyclotomy 5 */ CS4[50] = undef_dotval; /* undef_posdot - sqrt(2).hinvgold : can't occur */ CS4[51] = undef_dotval; /* one - sqrt(2).hinvgold : can't occur */ /* the matrix CS5 gives a + 2 cos.b, for b < 0, assuming cyclotomy 5, i.e., cos = hinvgold + half, 2 cos.cos = cos + half, 2 cos.hinvgold = half */ CS5[0] = locked; /* locked - 2 cos.cos */ CS5[1] = undef_dotval; /* undef_negdot - 2 cos.cos : can't occur */ CS5[2] = locked; /* - cos - 2 cos.cos */ CS5[3] = locked; /* - cos2 - 2 cos.cos */ CS5[4] = locked; /* - half - 2 cos.cos */ CS5[5] = locked; /* - hinvgold - 2 cos.cos */ CS5[6] = locked; /* zero - 2 cos.cos */ CS5[7] = locked; /* hinvgold - 2 cos.cos in cyclotomy 5 */ CS5[8] = neg_cos; /* half - 2 cos.cos in cyclotomy 5 */ CS5[9] = undef_dotval; /* cos2 - 2 cos.cos : can't occur */ CS5[10] = neg_half; /* cos - 2 cos.cos in cyclotomy 5 */ CS5[11] = undef_dotval; /* undef_posdot - 2 cos.cos : can't occur */ CS5[12] = neg_hinvgold; /* one - 2 cos.cos in cyclotomy 5 */ CS5[13] = locked; /* locked - 2 cos.cos2 */ CS5[14] = undef_dotval; /* undef_negdot - 2 cos.cos2 : can't occur */ CS5[15] = locked; /* - cos - 2 cos.cos2 */ CS5[16] = locked; /* - cos2 - 2 cos.cos2 */ CS5[17] = locked; /* - half - 2 cos.cos2 */ CS5[18] = locked; /* - hinvgold - 2 cos.cos2 : can't occur */ CS5[19] = locked; /* zero - 2 cos.cos2 */ CS5[20] = undef_dotval; /* hinvgold - 2 cos.cos2 : can't occur */ CS5[21] = undef_dotval; /* half - 2 cos.cos2 : can't occur */ CS5[22] = undef_dotval; /* cos2 - 2 cos.cos2 */ CS5[23] = undef_dotval; /* cos - 2 cos.cos2 : can't occur*/ CS5[24] = undef_dotval; /* undef_posdot - 2 cos.cos2 : can't occur */ CS5[25] = undef_dotval; /* one - 2 cos.cos2 : can't occur */ CS5[26] = locked; /* locked - cos */ CS5[27] = undef_dotval; /* undef_negdot - cos : can't occur */ CS5[28] = locked; /* - cos - cos */ CS5[29] = locked; /* - cos2 - cos */ CS5[30] = locked; /* - half - cos */ CS5[31] = locked; /* - hinvgold - cos = - sqrt(5)/2 < -1 */ CS5[32] = neg_cos; /* zero - cos */ CS5[33] = neg_half; /* hinvgold - cos */ CS5[34] = neg_hinvgold; /* half - cos */ CS5[35] = undef_dotval; /* cos2 - cos : can't occur */ CS5[36] = zero; /* cos - cos */ CS5[37] = undef_dotval; /* undef_posdot - cos : can't occur */ CS5[38] = undef_dotval; /* one - cos : can't occur */ CS5[39] = locked; /* locked - half */ CS5[40] = undef_dotval; /* undef_negdot - half : can't occur */ CS5[41] = locked; /* - cos - half */ CS5[42] = locked; /* - cos2 - half : can't occur */ CS5[43] = locked; /* - half - half */ CS5[44] = neg_cos; /* - hinvgold - half */ CS5[45] = neg_half; /* zero - half */ CS5[46] = undef_dotval; /* hinvgold - half : can't occur*/ CS5[47] = zero; /* half - half */ CS5[48] = undef_dotval; /* cos2 - half : can't occur */ CS5[49] = hinvgold; /* cos - half in cyclotomy 5 */ CS5[50] = undef_dotval; /* undef_posdot - half : can't occur */ CS5[51] = half; /* one - half */ /* the matrix CS6 gives a + sqrt(3).b, for b < 0, assuming cyclotomy 6, i.e., cos^2 = 3/2 */ CS6[0] = locked; /* locked - sqrt(3).cos */ CS6[1] = undef_dotval; /* undef_negdot - sqrt(3).cos : can't occur */ CS6[2] = locked; /* - cos - sqrt(3).cos */ CS6[3] = locked; /* - cos2 - sqrt(3).cos */ CS6[4] = locked; /* - half - sqrt(3).cos */ CS6[5] = locked; /* - hinvgold - sqrt(3).cos */ CS6[6] = locked; /* zero - sqrt(3).cos */ CS6[7] = undef_dotval; /* hinvgold - sqrt(3).cos : can't occur */ CS6[8] = locked; /* half - sqrt(3).cos in cyclotomy 6 */ CS6[9] = undef_dotval; /* cos2 - sqrt(3).cos : can't occur */ CS6[10] = undef_dotval; /* cos - sqrt(3).cos : can't occur */ CS6[11] = undef_dotval; /* undef_posdot - sqrt(3).cos : can't occur */ CS6[12] = neg_half; /* one - sqrt(3).cos in cyclotomy 6*/ CS6[13] = locked; /* locked - sqrt(3).cos2 */ CS6[14] = undef_dotval; /* undef_negdot - sqrt(3).cos2 : can't occur */ CS6[15] = locked; /* - cos - sqrt(3).cos2 */ CS6[16] = locked; /* - cos2 - sqrt(3).cos2 */ CS6[17] = locked; /* - half - sqrt(3).cos2 */ CS6[18] = locked; /* - hinvgold - sqrt(3).cos2 */ CS6[19] = locked; /* zero - sqrt(3).cos2 */ CS6[20] = undef_dotval; /* hinvgold - sqrt(3).cos2 : can't occur */ CS6[21] = undef_dotval; /* half - sqrt(3).cos2 : can't occur */ CS6[22] = undef_dotval; /* cos2 - sqrt(3).cos2 : can't occur */ CS6[23] = undef_dotval; /* cos - sqrt(3).cos2 : can't occur*/ CS6[24] = undef_dotval; /* undef_posdot - sqrt(3).cos2 : can't occur */ CS6[25] = undef_dotval; /* one - sqrt(3).cos2 : can't occur */ CS6[26] = locked; /* locked - sqrt(3).half */ CS6[27] = undef_dotval; /* undef_negdot - sqrt(3).half : can't occur */ CS6[28] = locked; /* - cos - sqrt(3).half */ CS6[29] = locked; /* - cos2 - sqrt(3).half */ CS6[30] = locked; /* - half - sqrt(3).half */ CS6[31] = locked; /* - hinvgold - sqrt(3).half */ CS6[32] = neg_cos; /* zero - sqrt(3).half */ CS6[33] = undef_dotval; /* hinvgold - sqrt(3).half : can't occur */ CS6[34] = undef_dotval; /* half - sqrt(3).half : can't occur */ CS6[35] = undef_dotval; /* cos2 - sqrt(3).half : can't occur */ CS6[36] = zero; /* cos - sqrt(3).half in cyclotomy 6 */ CS6[37] = undef_dotval; /* undef_posdot - sqrt(3).half : can't occur */ CS6[38] = undef_dotval; /* one - sqrt(3).half : can't occur */ CS6[39] = locked; /* locked - sqrt(3).hinvgold */ CS6[40] = undef_dotval; /* undef_negdot - sqrt(3).hinvgold : can't occur */ CS6[41] = locked; /* - cos - sqrt(3).hinvgold */ CS6[42] = locked; /* - cos2 - sqrt(3).hinvgold */ CS6[43] = locked; /* - half - sqrt(3).hinvgold */ CS6[44] = undef_dotval; /* - hinvgold - sqrt(3).hinvgold : can't occur */ CS6[45] = undef_dotval; /* zero - sqrt(3).hinvgold : can't occur */ CS6[46] = undef_dotval; /* hinvgold - sqrt(3).hinvgold : can't occur*/ CS6[47] = undef_dotval; /* half - sqrt(3).hinvgold : can't occur */ CS6[48] = undef_dotval; /* cos2 - sqrt(3).hinvgold : can't occur */ CS6[49] = undef_dotval; /* cos - sqrt(3).hinvgold : can't occur */ CS6[50] = undef_dotval; /* undef_posdot - sqrt(3).hinvgold : can't occur */ CS6[51] = undef_dotval; /* one - sqrt(3).hinvgold : can't occur */ /* the matrix CSm gives a + 2 2 cos.b, for b < 0, assuming cyclotomy m > 6 we have the identities c_m.cos(pi/m) = cos(pi/m) + 1, c_m.cos(2pi/m) = cos(3pi/m) + cos(pi/m) and since cos(3pi/7) + cos(pi/7) = 1 + cos(2pi/7) > 2, c_m.cos(2pi/m) > 2 for all m > 6 */ CSm[-13] = locked; /* locked - c_m.cos(*) */ CSm[-12] = locked; /* undef_negdot - c_m.cos(*) */ CSm[-11] = locked; /* - cos - c_m.cos(*) */ CSm[-10] = locked; /* - cos2 - c_m.cos(*) */ CSm[-9] = undef_dotval; /* - half - c_m.cos(*) : can't occur */ CSm[-8] = undef_dotval; /* - hinvgold - c_m.cos(*) : can't occur */ CSm[-7] = undef_dotval; /* zero - c_m.cos(*) : can't occur */ CSm[-6] = undef_dotval; /* hinvgold - c_m.cos(*) : can't occur */ CSm[-5] = undef_dotval; /* half - c_m.cos(*) : can't occur */ CSm[-4] = undef_negdot; /* cos2 - c_m.cos(*) */ CSm[-3] = undef_dotval; /* cos - c_m.cos(*) : can't occur*/ CSm[-2] = undef_negdot; /* undef_posdot - c_m.cos(*) */ CSm[-1] = undef_dotval; /* one - c_m.cos(*) : can't occur */ CSm[0] = locked; /* locked - c_m.cos */ CSm[1] = undef_dotval; /* undef_negdot - c_m.cos : can't occur */ CSm[2] = locked; /* - cos - c_m.cos */ CSm[3] = locked; /* - cos2 - c_m.cos */ CSm[4] = locked; /* - half - c_m.cos */ CSm[5] = locked; /* - hinvgold - c_m.cos */ CSm[6] = locked; /* zero - c_m.cos */ CSm[7] = undef_dotval; /* hinvgold - c_m.cos : can't occur */ CSm[8] = locked; /* half - c_m.cos */ CSm[9] = locked; /* cos2 - c_m.cos = -1 */ CSm[10] = undef_dotval; /* cos - c_m.cos : can't occur*/ CSm[11] = undef_dotval; /* undef_posdot - c_m.cos : can't occur */ CSm[12] = neg_cos2; /* one - c_m.cos */ CSm[13] = locked; /* locked - c_m.cos2 */ CSm[14] = undef_dotval; /* undef_negdot - c_m.cos2 : can't occur */ CSm[15] = locked; /* - cos - c_m.cos2 */ CSm[16] = locked; /* - cos2 - c_m.cos2 */ CSm[17] = locked; /* - half - c_m.cos2 */ CSm[18] = locked; /* - hinvgold - c_m.cos2 */ CSm[19] = locked; /* zero - c_m.cos2 */ CSm[20] = undef_dotval; /* hinvgold - c_m.cos2 : can't occur */ CSm[21] = undef_dotval; /* half - c_m.cos2 : can't occur */ CSm[22] = locked; /* cos2 - c_m.cos2 : can't occur */ CSm[23] = undef_negdot; /* cos - c_m.cos2 = -cos3 */ CSm[24] = undef_dotval; /* undef_posdot - c_m.cos2 : can't occur */ CSm[25] = undef_dotval; /* one - c_m.cos2 : can't occur */ CSm[26] = locked; /* locked - c_m.half */ CSm[27] = undef_dotval; /* undef_negdot - c_m.half : can't occur */ CSm[28] = locked; /* - cos - c_m.half */ CSm[29] = locked; /* - cos2 - c_m.half */ CSm[30] = locked; /* - half - c_m.half */ CSm[31] = locked; /* - hinvgold - c_m.half */ CSm[32] = neg_cos; /* zero - c_m.half */ CSm[33] = undef_dotval; /* hinvgold - c_m.half : can't occur */ CSm[34] = undef_dotval; /* half - c_m.half : can't occur */ CSm[35] = undef_dotval; /* cos2 - c_m.half : can't occur */ CSm[36] = zero; /* cos - c_m.half */ CSm[37] = undef_dotval; /* undef_posdot - c_m.half : can't occur */ CSm[38] = half; /* one - c_m.half : can't occur */ CSm[39] = locked; /* locked - c_m.hinvgold */ CSm[40] = undef_dotval; /* undef_negdot - c_m.hinvgold : can't occur */ CSm[41] = locked; /* - cos - c_m.hinvgold */ CSm[42] = locked; /* - cos2 - c_m.hinvgold */ CSm[43] = locked; /* - half - c_m.hinvgold */ CSm[44] = undef_dotval; /* - hinvgold - c_m.hinvgold : can't occur */ CSm[45] = undef_dotval; /* zero - c_m.hinvgold : can't occur */ CSm[46] = undef_dotval; /* hinvgold - c_m.hinvgold : can't occur */ CSm[47] = undef_dotval; /* half - c_m.hinvgold : can't occur */ CSm[48] = undef_dotval; /* cos2 - c_m.hinvgold : can't occur */ CSm[49] = undef_dotval; /* cos - c_m.hinvgold : can't occur */ CSm[50] = undef_dotval; /* undef_posdot - c_m.hinvgold : can't occur */ CSm[51] = undef_dotval; /* one - c_m.hinvgold : can't occur */ return; } }; /**************************************************************************** Chapter I -- The InitMinTable class. This section defines the class InitMinTable class, which is used in the construction of MinTable. NOTE : this looks a rather clumsy, and could probably be improved. The problem is that the constructing functions need access to the representation, but we don't want them to be member functions. An alternative would be to make them private members. ****************************************************************************/ namespace { InitMinTable::InitMinTable(CoxGraph& G) { static InitStaticConstants a; d_rank = G.rank(); initMinTable(G); return; } void InitMinTable::initMinTable(CoxGraph& G) { d_min.setSize(rank()); d_dot.setSize(rank()); d_min[0] = new(arena()) MinNbr[rank()*rank()]; d_dot[0] = new(arena()) DotProduct[rank()*rank()]; for (Generator s = 1; s < rank(); s++) { d_dot[s] = d_dot[s-1] + rank(); d_min[s] = d_min[s-1] + rank(); } for (MinNbr r = 0; r < rank(); r++) { for (Generator s = 0; s < rank(); s++) switch (G.M(r,s)) { case 0: d_dot[r][s] = locked; d_min[r][s] = not_minimal; break; case 1: d_dot[r][s] = dotval::one; d_min[r][s] = not_positive; break; case 2: d_dot[r][s] = zero; d_min[r][s] = r; break; case 3: d_dot[r][s] = neg_half; d_min[r][s] = dihedral; break; default: d_dot[r][s] = neg_cos; d_min[r][s] = dihedral; break; }; } d_size = rank(); return; } MinNbr InitMinTable::dihedralShift(MinNbr r, Generator s, Generator t, Ulong c) /* This function shifts r by stst... (c terms). */ { Ulong j; Generator u; u = s; for (j = 0; j < c; j++) { if (min(r,u) >= undef_minnbr) return min(r,u); r = min(r,u); if (u == s) u = t; else u = s; } return r; } void InitMinTable::fillDihedralRoots(CoxGraph& G) /* Assuming M has been initialized by InitMinTable, fills in the rows corresponding to the dihedral roots. */ { MinNbr r = 0; /* fill in roots of depth 1 */ for (; r < rank(); ++r) { for (Generator s = 0; s < rank(); ++s) if (min(r,s) == dihedral) { newDepthOneRoot(G,r,s); d_size++; } } /* fill in roots of depth 2 */ MinNbr c = d_size; for (; r < c; ++r) { for (Generator s = 0; s < rank(); ++s) if (min(r,s) == dihedral) { newDepthTwoRoot(G,r,s); d_size++; } } /* fill in roots of depth > 2 */ for (Length d = 3; r < d_size; ++d) { c = d_size; for (; r < c; ++r) { for (Generator s = 0; s < rank(); ++s) if (min(r,s) == dihedral) { newDihedralRoot(G,r,s,d); d_size++; } } } return; } void InitMinTable::fillDepthOneRow(CoxGraph& G, MinNbr r, Generator s) { Generator u = min(r,s); MinNbr* ps = d_min[s]; for (Generator t = 0; t < rank(); t++) { if (t == s) continue; if (t == u) { /* t is the other element in the support */ CoxEntry m = G.M(s,t); if (m == 3) { /* descent */ d_min[r][t] = s; ps[t] = r; } else if (m == 4) /* commutation */ d_min[r][t] = r; else d_min[r][t] = dihedral; continue; } switch (dot(r,t)) { case zero: d_min[r][t] = r; break; case neg_cos2: case neg_half: case neg_cos: d_min[r][t] = undef_minnbr; break; case locked: d_min[r][t] = not_minimal; break; default: break; } } return; } void InitMinTable::fillDihedralRow(CoxGraph& G, MinNbr r, Generator s, Length d) { MinNbr p = min(r,s); for (Generator t = 0; t < rank(); t++) { if (t == s) continue; if (min(p,t) < p) { /* t is the other element in the support */ if (dot(r,t) < 0) d_min[r][t] = dihedral; else if (dot(r,t) == 0) d_min[r][t] = r; else { /* descent */ CoxEntry m = G.M(s,t); MinNbr y; switch (m % 4) { case 0: case 2: d_min[r][t] = r; break; case 1: y = dihedralShift(t,s,t,d-1); d_min[r][t] = y; d_min[y][t] = r; break; case 3: y = dihedralShift(s,t,s,d-1); d_min[r][t] = y; d_min[y][t] = r; break; } } continue; } switch (dot(r,t)) { case zero: d_min[r][t] = r; break; case neg_cos2: case neg_half: case neg_cos: d_min[r][t] = undef_minnbr; break; case locked: d_min[r][t] = not_minimal; break; default: break; } } return; } void InitMinTable::fillReflectionRow(CoxGraph& G, MinNbr r, Generator s) /* This function fills in d_min[r], where r has just been created through s, and d_dot[r] is filled in. It is assumed that d_min[r][s] is already filled in. */ { for (Generator t = 0; t < rank(); t++) { if (t == s) continue; switch (dot(r,t)) { case dotval::cos: case cos2: case half: /* descent */ case hinvgold: if (G.star(bits::lmask[t],s)) { /* M(t,s) > 2 */ CoxEntry m = G.M(s,t); MinNbr y = dihedralShift(r,s,t,2*m-1); d_min[r][t] = y; d_min[y][t] = r; } else { /* commuting descent */ MinNbr y; y = min(r,s); y = min(y,t); y = min(y,s); d_min[r][t] = y; d_min[y][t] = r; } break; case zero: d_min[r][t] = r; break; case neg_hinvgold: case neg_half: case neg_cos2: case neg_cos: d_min[r][t] = undef_minnbr; break; case locked: d_min[r][t] = not_minimal; break; default: break; } } return; } void InitMinTable::fillMinTable(CoxGraph& G) { fillDihedralRoots(G); for (Ulong r = rank(); r < d_size; r++) { for (Generator s = 0; s < rank(); ++s) if (min(r,s) == undef_minnbr) { newMinRoot(G,r,s); d_size++; // printf("%d\r",d_size); // count roots } } // printf("\n"); return; } void InitMinTable::newDepthOneRoot(CoxGraph& G, MinNbr r, Generator s) { setMinMemory(d_size+1); d_min[d_size]= new(arena()) MinNbr[rank()]; d_dot[d_size]= new(arena()) DotProduct[rank()]; d_min[d_size][s] = r; d_min[r][s] = d_size; memcpy(d_dot[d_size],d_dot[r],rank()*sizeof(DotProduct)); d_dot[d_size][s] = -d_dot[d_size][s]; for (LFlags f = G.star(s); f; f &= f-1) { Generator t = bits::firstBit(f); if (dot(r,t) == locked) continue; d_dot[d_size][t] = bondCosineSum(G.M(s,t),dot(r,t),dot(r,s)); } fillDepthOneRow(G,d_size,s); return; } void InitMinTable::newDepthTwoRoot(CoxGraph& G, MinNbr r, Generator s) { setMinMemory(d_size+1); d_min[d_size]= new(arena()) MinNbr[rank()]; d_dot[d_size]= new(arena()) DotProduct[rank()]; d_min[d_size][s] = r; d_min[r][s] = d_size; memcpy(d_dot[d_size],d_dot[r],rank()*sizeof(DotProduct)); d_dot[d_size][s] = -d_dot[d_size][s]; for (LFlags f = G.star(s); f; f &= f-1) { Generator t = bits::firstBit(f); if (dot(r,t) == locked) continue; d_dot[d_size][t] = bondCosineSum(G.M(s,t),dot(r,t),dot(r,s)); } fillDihedralRow(G,d_size,s,2); return; } void InitMinTable::newDihedralRoot(CoxGraph& G, MinNbr r, Generator s, Length d) { setMinMemory(d_size+1); d_min[d_size]= new(arena()) MinNbr[rank()]; d_dot[d_size]= new(arena()) DotProduct[rank()]; d_min[d_size][s] = r; d_min[r][s] = d_size; memcpy(d_dot[d_size],d_dot[r],rank()*sizeof(DotProduct)); d_dot[d_size][s] = -d_dot[d_size][s]; for (LFlags f = G.star(s); f; f &= f-1) { Generator t = bits::firstBit(f); if (dot(r,t) == locked) continue; CoxEntry m = G.M(s,t); d_dot[d_size][t] = bondCosineSum(m,dot(r,t),dot(r,s)); /* correction if maximal depth is reached */ if (dot(d_size,t) == undef_negdot) /* t is the other element */ if (d == (m-1)/2) d_dot[d_size][t] = -d_dot[d_size][t]; } fillDihedralRow(G,d_size,s,d); return; } void InitMinTable::newMinRoot(CoxGraph& G, MinNbr r, Generator s) { setMinMemory(d_size+1); d_min[d_size]= new(arena()) MinNbr[rank()]; d_dot[d_size]= new(arena()) DotProduct[rank()]; d_min[d_size][s] = r; d_min[r][s] = d_size; memcpy(d_dot[d_size],d_dot[r],rank()*sizeof(DotProduct)); d_dot[d_size][s] = -d_dot[d_size][s]; for (LFlags f = G.star(s); f; f &= f-1) { Generator t = bits::firstBit(f); if (dot(r,t) == locked) continue; d_dot[d_size][t] = bondCosineSum(G.M(s,t),dot(r,t),dot(r,s)); } fillReflectionRow(G,d_size,s); return; } }; /**************************************************************************** Chapter II -- The MinTable class. This section defines the functions in the MinTable class. The following functions are defined : - MinTable(CoxGraph&); - fill(CoxGraph&) : fills the MinTable; access to the descent sets : - descent(g) : two-sided descent set; - ldescent(g) : left descent set; - rdescent(g) : right descent set; the fundamental string operations which are the raison d'etre of minroot tables : - insert(g,s) : inserts the generator s into the normal form g; - inverse(g) : transforms g into its inverse; - isDescent(g,s) : tels whether or not gs < g; - normalForm(g,order) : transforms g into the shortlex normal form for order; - prod(g,s),prod(g,h) : transforms g into gs (gh); - reduced(g,h) : writes in g a reduced expression for the string h; elementary Bruhat order access~: - inOrder(g,h) : tells whether g <= h; - inOrder(a,g,h) : tells whether g <= h, and catches the reduction points; ****************************************************************************/ namespace minroots { MinTable::MinTable(CoxGraph& G) { new(this) InitMinTable(G); return; } MinTable::~MinTable() /* The things that have to be destructed are the tables d_min and d_dot. They have been allocated on a per-element basis, each row having a fixed size (except for the first allocation, which is for d_rank elements.) NOTE : this is another instance where things can be made cleaner and more efficient by having min and dot have their own arenas. */ { /* undo general allocations */ for (Ulong j = d_rank; j < d_min.size(); ++j) { arena().free(d_min[j],d_rank*sizeof(MinNbr)); } for (Ulong j = d_rank; j < d_dot.size(); ++j) { arena().free(d_dot[j],d_rank*sizeof(DotProduct)); } /* undo first allocation */ arena().free(d_min[0],d_rank*d_rank*sizeof(MinNbr)); arena().free(d_dot[0],d_rank*d_rank*sizeof(DotProduct)); return; } LFlags MinTable::descent(const CoxWord& g) const /* Returns the two-sided descent set of g, in the usual format : the right descent set is contained in the rank rightmost bits, the left descent set in the next rank bits. */ { static CoxWord h(0); LFlags f = 0; for (Generator s = 0; s < d_rank; ++s) { if (isDescent(g,s)) f |= lmask[s]; } h = g; inverse(h); for (Generator s = 0; s < d_rank; ++s) { if (isDescent(h,s)) f |= lmask[d_rank+s]; } return f; } LFlags MinTable::ldescent(const CoxWord& g) const /* Returns the left descent set of g. */ { static CoxWord h(0); h = g; inverse(h); LFlags f = 0; for (Generator s = 0; s < d_rank; ++s) { if (isDescent(h,s)) f |= lmask[s]; } return f; } LFlags MinTable::rdescent(const CoxWord& g) const /* Returns the right descent set of g. */ { LFlags f = 0; for (Generator s = 0; s < d_rank; ++s) { if (isDescent(g,s)) f |= lmask[s]; } return f; } void MinTable::fill(CoxGraph& G) { InitMinTable* T = (InitMinTable *)this; T->fillMinTable(G); } int MinTable::insert(CoxWord& g, const Generator& s, const Permutation& order) const /* This function is like prod below, except that it is now assumed that g is a ShortLex Normal form (always w.r.t. the ordering defined by order), and we wish the result to be again a normal form. It is known that this will be achieved by an appropriate insertion or deletion. More precisely, if the word gs is non-reduced, there is only one possible deletion point, which will be found as in prod; when the word is reduced, the appropriate insertion point and generator is also given by the minimal root machine : in the notation below, we will have to send an alert each time that s_{j}...s_{p}s = ts_{j}...s_{p} for some generator t, and this will yield a lexicographically smaller reduced expression if t < s_{j}. As below, the return value is +1 if gs is reduced, -1 otherwise. */ { MinNbr r = s; Generator i = s; Length p = g.length(); Ulong q = p; for (Ulong j = p; j;) { --j; r = min(r,g[j]-1); if (r == not_positive) { /* reduction */ g.erase(j); return -1; } if ((r < rank()) && (order[r] < order[g[j]-1])) { /* better insertion point */ i = r; q = j; } if (r == not_minimal) /* no further insertions */ break; } /* if we get here g.s is reduced */ g.insert(q,i+1); return 1; } bool MinTable::inOrder(const CoxWord& d_g, const CoxWord& d_h) const /* This function tells whether g <= h using the well-known elementary algorithm : choose s s.t. hs < h; then if gs < g, we have g <= h iff gs <= hs; else g <= h iff g <= hs. As always, it is assumed that g and h are reduced expressions. */ { CoxWord g(d_g); CoxWord h(d_h); while (h.length()) { if (g.length() > h.length()) return false; Generator s = h[h.length()-1]-1; // last term of h if (isDescent(g,s)) prod(g,s); h.erase(h.length()-1); } return true; } bool MinTable::inOrder(List& a, const CoxWord& d_g, const CoxWord& d_h) const /* Like the previous inOrder, but puts in a the places where the erasures take place. The list a is not disturbed if the comparison yields false. */ { CoxWord g(d_g); CoxWord h(d_h); List b(0); if (g.length() > h.length()) return false; while (h.length()) { Generator s = h[h.length()-1]-1; // last term of h if (isDescent(g,s)) prod(g,s); else /* there is an erasure */ b.append(h.length()-1); h.erase(h.length()-1); if (g.length() > h.length()) return false; } a.setSize(b.size()); // copy b to a in opposite order for (Ulong j = 0; j < b.size(); ++j) a[a.size()-1-j] = b[j]; return true; } const CoxWord& MinTable::inverse(CoxWord& g) const /* Inverses g. As we have made the assummption that only reduced words enter the program, this is trivial! We only return a reduced expression, not necessarily a normal form. NOTE : this has nothing to do with the minroot table, but it has seemed better to regroup all the elementary string operations in one place. */ { Length p = g.length(); for (Length j = 0; j < p/2; ++j) { CoxLetter u = g[p-j-1]; g[p-j-1] = g[j]; g[j] = u; } return g; } bool MinTable::isDescent(const CoxWord& g, const Generator& s) const /* Returns true if s is a descent generator of g, false otherwise. */ { MinNbr r = s; for (Ulong j = g.length(); j;) { --j; Generator t = g[j]-1; r = min(r,t); if (r == not_positive) { /* found reduction */ return true; } if (r == not_minimal) /* no reduction */ return false; } /* if we get here g.s is reduced */ return false; } const CoxWord& MinTable::normalForm(CoxWord& g, const Permutation& order) const /* Transforms g into its shortlex normal form (as defined by order) by a sequence of insertions. As always, it is assumed that g is reduced. */ { Ulong p = g.length(); g.setLength(p-1); g.insert(0,0); g.setLength(0); for (Ulong j = 0; j < p; ++j) insert(g,g[j+1]-1,order); return g; } const CoxWord& MinTable::power(CoxWord& g, const Ulong& m) const /* Raises a to the m-th power. This can be done very quickly, by squarings and multiplications with the original value of a (stored in b), by looking at the bit-pattern of m. */ { static Ulong hi_bit = (Ulong)1 << BITS(Ulong) - 1; if (m == 0) { /* result is identity */ g.reset(); return g; } CoxWord h = g; Ulong p; for (p = m; ~p & hi_bit; p <<= 1) /* shift m up to high powers */ ; for (Ulong j = m >> 1; j; j >>= 1) { p <<= 1; prod(g,g); /* g = g*g */ if (p & hi_bit) prod(g,h); /* g = g*h */ } return g; } int MinTable::prod(CoxWord& g, const Generator& s) const /* This is the fundamental function provided by the mintable structure. It takes as input a coxword g, assumed to be reduced, as all words in this program, an transforms it into gs by doing an appropriate insertion or deletion. It returns +1 if the length goes up, -1 if the length goes down. As we are not concerned about normal forms, we always insert at the end --- this is a bit more efficient. To insert into a normal form, see insert. The algorithm works as follows (cf. Brink and Howlett) : let p = l(g). The only way g.s can be non-reduced is if there is a j <= p such that s_{j+1}...s_{p}s = s_{j}...s_{p}, i.e. s_{j+1}...s_{p}a_{s} = a_{s_j}, if we denote by a_{t} the simple root corresponding to t. So all we have to do is follow the sequence of {s_k}...{s_p}a_{s} in the mintable, and send an alert each time we get to a simple root (in fact, it will be enough to check for the shift to not_positive.) The wonderful thing --- the main theorem in B&H --- is that when we reach a value not_minimal in the mintable, we can stop altogether : the word is reduced. */ { MinNbr r = s; Length p = g.length(); for (Ulong j = p; j;) { --j; Generator t = g[j]-1; r = min(r,t); if (r == not_positive) { /* found reduction */ g.erase(j); return -1; } if (r == not_minimal) /* no reduction */ break; } /* if we get here g.s is reduced */ g.setLength(p+1); g[p] = s+1; g[p+1] = '\0'; return 1; } int MinTable::prod(CoxWord& g, CoxLetter *const h, const Ulong& n) const /* Does the product consecutively by the letters in h. Returns the length difference. */ { int p = 0; for (Ulong j = 0; j < n; ++j) { Generator s = h[j] - 1; p += prod(g,s); } return p; } int MinTable::prod(CoxWord& g, const CoxWord& h) const /* Does the product consecutively by the letters in h. Returns the length difference. NOTE : needs to save h in buf because it might be that h = g. */ { static CoxWord buf(0); buf = h; int p = 0; for (Ulong j = 0; j < buf.length(); ++j) { Generator s = buf[j] - 1; p += prod(g,s); } return p; } const CoxWord& MinTable::reduced(CoxWord& g, CoxWord& h) const /* Writes in g a reduced word corresponding to the arbitrary generator string h. This is the only instance in the whole program where a coxword might be non-reduced; it is not used in the program, but provided for convenience. */ { g.setLength(0); g[0] = 0; for (Ulong j = 0; j < h.length(); ++j) prod(g,h[j]-1); return g; } }; /**************************************************************************** Chapter III -- Auxiliary functions This section defines some ausiliary functions defined in this module : - bondCosineSum(CoxEntry,int,int) : defines the symbolic sum of a and b for bonds of type m; ****************************************************************************/ namespace { DotVal bondCosineSum(CoxEntry m, int a, int b) { int j = a - first_dotval, k = b - first_negdotval; switch (m) { case 3: return CS3[k*dotval_size + j]; case 4: return CS4[k*dotval_size + j]; break; case 5: return CS5[k*dotval_size + j]; break; case 6: return CS6[k*dotval_size + j]; break; default: return CSm[k*dotval_size + j]; break; } } }; /**************************************************************************** Chapter IV - Root information This section defines some functions providing information about the actual roots. The following functions are provided : - depth(T,r) : returns the depth of r (offset by 1 from the definition in Brink-Howlett, for better or for worse.) - descent(T,r) : returns the descent set of r; - reduced(T,r) : returns a reduced expression for the reflection corresponding to r in W; - support(T,r) : returns the support of the root r; ****************************************************************************/ Length minroots::depth(MinTable& T, MinNbr r) { Length d = 0; MinNbr& rv = r; while(1) { Generator s; for (s = 0; s < T.rank(); ++s) if (T.min(r,s) < rv) break; if (s == T.rank()) break; ++d; rv = T.min(r,s); } return d; } LFlags minroots::descent(MinTable& T, MinNbr r) { LFlags A = 0; for (Ulong j = 0; j < T.rank(); ++j) if (T.dot(r,j) > 0) A |= bits::lmask[j]; return A; } CoxWord& minroots::reduced(MinTable& T, MinNbr r) /* Returns a reduced expression for the reflection corresponding to r. The expression is returned in &buf, which is a safe place until the next call to reduced. */ { static CoxWord buf(0); Length d = 0; while (1) { Generator s; for (s = 0; s < T.rank(); s++) if (T.min(r,s) < r) break; if (s == T.rank()) break; buf.setLength(d); buf[d] = s+1; r = T.min(r,s); d++; } buf.setLength(2*d+1); buf[d] = r+1; for (Length j = 1; j <= d; j++) buf[d+j] = buf[d-j]; buf[2*d+1] = '\0'; return buf; } LFlags minroots::support(MinTable& T, MinNbr r) /* Returns the support fo the root of index r. */ { LFlags f = 0; while(1) { Generator s; for (s = 0; s < T.rank(); ++s) if (T.min(r,s) < r) break; if (s == T.rank()) break; f |= bits::lmask[s]; r = T.min(r,s); } return f | bits::lmask[r]; } /**************************************************************************** Chapter IV - Input/Output This section provides input/output operations for the classes defined in this module. The following functions are provided : - append(str,a) : appends a DotVal to the string; - print(file,T) : prints the table; ****************************************************************************/ String& append(String& str, const DotVal& a) { switch (a) { case undef_dotval: io::append(str,"undef_minnbr"); return str; case undef_negdot: io::append(str,"-c(*)/2"); return str; case locked : io::append(str,"*"); return str; case neg_cos : io::append(str,"-c/2"); return str; case neg_cos2 : io::append(str,"-c(2)/2"); return str; case neg_half : io::append(str,"-1/2"); return str; case neg_hinvgold : io::append(str,"-c(2,5)/2"); return str; case zero : io::append(str,"0"); return str; case hinvgold : io::append(str,"c(2,5)/2"); return str; case half : io::append(str,"1/2"); return str; case cos2 : io::append(str,"c(2)/2"); return str; case dotval::cos : io::append(str,"c/2"); return str; case dotval::one : io::append(str,"1"); return str; case undef_posdot: io::append(str,"c(*)/2"); return str; default: // should not happen return str; }; } void minroots::print(FILE *file, MinTable& T) /* This function prints out the abstract minimal root table, without reference to any explicit geometric or combinatorial representation. The vertices are enumerated in a sort of "short-lex" order (depth-first, always looking at first descent; this will in fact be "inverse short lex" toward the center.) */ { MinNbr r; MinNbr& rv = r; int d = io::digits(T.size()-1,10); /* largest possible value */ for (rv = 0; rv < T.size(); ++rv) { fprintf(file," %*u : ",d,rv); for (Generator s = 0; s < T.rank(); s++) switch (T.min(r,s)) { case undef_minnbr: case dihedral: fprintf(file,"%*s",d+1,"*"); break; case not_minimal: fprintf(file,"%*s",d+1,"+"); break; case not_positive: fprintf(file,"%*s",d+1,"-"); break; default: fprintf(file,"%*u",d+1,T.min(r,s)); break; }; fprintf(file,"\n"); } return; } positivity_final/minroots.h0000600000175000017500000000707710011171251017655 0ustar duclouxducloux00000000000000/* This is minroots.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef MINROOTS_H /* guarantee single inclusion */ #define MINROOTS_H #include #include "globals.h" namespace minroots { using namespace globals; }; /******** type declarations *************************************************/ namespace minroots { typedef unsigned MinNbr; typedef char DotProduct; class MinTable; }; /* constants */ namespace minroots { const MinNbr MINNBR_MAX = UINT_MAX-4; /* top values are reserved */ const MinNbr MINROOT_MAX = MINNBR_MAX; /* should not exceed MINNBR_MAX */ const MinNbr undef_minnbr = MINNBR_MAX + 1; const MinNbr not_minimal = MINNBR_MAX + 2; const MinNbr not_positive = MINNBR_MAX + 3; }; /******** function declarations *********************************************/ #include "bits.h" #include "coxtypes.h" #include "dotval.h" #include "io.h" namespace minroots { using namespace bits; using namespace coxtypes; using namespace dotval; using namespace io; }; namespace minroots { String& append(String& str, const DotVal& a); LFlags descent(MinTable& T, MinNbr r); Length depth(MinTable& T, MinNbr r); void print(FILE *file, MinTable& T); CoxWord& reduced(MinTable& T, MinNbr r); LFlags support(MinTable& T, MinNbr r); }; /******* type definitions ****************************************************/ #include "graph.h" #include "list.h" #include "memory.h" namespace minroots { using namespace graph; using namespace list; using namespace memory; }; class minroots::MinTable { protected: Rank d_rank; MinNbr d_size; List d_min; List d_dot; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(MinTable));} void* operator new(size_t, void* ptr) {return ptr;} void operator delete(void* ptr, void* placement) {}; MinTable() {}; MinTable(CoxGraph& G); ~MinTable(); /* manipulators */ void fill(CoxGraph& G); /* accessors */ LFlags descent(const CoxWord& g) const; DotVal dot(MinNbr r, Generator s) const; /* inlined */ int insert(CoxWord& g, const Generator& s, const Permutation& order) const; const CoxWord& inverse(CoxWord& g) const; bool inOrder(const CoxWord& g, const CoxWord& h) const; bool inOrder(List& a, const CoxWord& g, const CoxWord& h) const; bool isDescent(const CoxWord& g, const Generator& s) const; LFlags ldescent(const CoxWord& g) const; const CoxWord& normalForm(CoxWord& g, const Permutation& order) const; MinNbr min(MinNbr r, Generator s) const; /* inlined */ int prod(CoxWord& g, const Generator& s) const; int prod(CoxWord& g, CoxLetter *const h, const Ulong& n) const; int prod(CoxWord& g, const CoxWord& h) const; Rank rank() const; /* inlined */ LFlags rdescent(const CoxWord& g) const; const CoxWord& reduced(CoxWord& g, CoxWord& h) const; MinNbr size() const; /* inlined */ const CoxWord& power(CoxWord& a, const Ulong& m) const; }; /******** Inline definitions **********************************************/ namespace minroots { inline DotVal MinTable::dot(MinNbr r, Generator s) const {return DotVal(d_dot[r][s]);} inline MinNbr MinTable::min(MinNbr r, Generator s) const {return d_min[r][s];} inline Rank MinTable::rank() const {return d_rank;} inline MinNbr MinTable::size() const {return d_size;} }; #endif positivity_final/polynomials.cpp0000600000175000017500000000000010011171251020657 0ustar duclouxducloux00000000000000positivity_final/polynomials.h0000600000175000017500000001756710116066003020362 0ustar duclouxducloux00000000000000/* This is polynomials.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef POLYNOMIALS_H /* include guard */ #define POLYNOMIALS_H #include "globals.h" #include namespace polynomials { using namespace globals; }; /******** type declarations **************************************************/ namespace polynomials { typedef Ulong Degree; typedef long SDegree; class Monomial; template class Polynomial; template class LaurentPolynomial; }; /******** constants **********************************************************/ namespace polynomials { const Degree undef_degree = ~0; const Degree DEGREE_MAX = ULONG_MAX-1; const SDegree SDEGREE_MAX = LONG_MAX; const SDegree SDEGREE_MIN = LONG_MIN+1; const SDegree undef_valuation = LONG_MIN; }; /******** function definitions ***********************************************/ #include "io.h" namespace polynomials { using namespace io; }; namespace polynomials { template bool operator== (const Polynomial& p, const Polynomial& q); template bool operator!= (const Polynomial& p, const Polynomial& q); template bool operator<= (const Polynomial& p, const Polynomial& q); template bool operator>= (const Polynomial& p, const Polynomial& q); template bool operator< (const Polynomial& p, const Polynomial& q); template bool operator> (const Polynomial& p, const Polynomial& q); template String& append(String& str, const Polynomial &p, const char *x); template String& append(String& str, const Polynomial& p, const Degree& d, const long& m, const char *x); template String& append(String& str, const Polynomial& p, const Degree& d, const long& m, const char *x,GAP); template String& append(String& str, const Polynomial& p, const Degree& d, const long& m, const char *x,Terse); template void print(FILE* file, const Polynomial& p, const char *x); template void print(FILE* file, const LaurentPolynomial& p, const char *x); template void print(FILE* file, const Polynomial& p, const Degree& d, const long& m, const char *x); template void print(FILE* file, const Polynomial& p, const Degree& d, const long& m, const char *x,GAP); template void print(FILE* file, const Polynomial& p, const Degree& d, const long& m, const char *x,Terse); template SDegree sumDegree(const LaurentPolynomial& p, const LaurentPolynomial& q); template SDegree sumValuation(const LaurentPolynomial& p, const LaurentPolynomial& q); }; /******** type definitions ***************************************************/ #include "vector.h" namespace polynomials { using namespace vector; }; namespace polynomials { template class Polynomial { protected: Vector v; public: typedef struct {} const_tag; /* constructors and destructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(Polynomial));} Polynomial(){}; Polynomial(Degree d):v(d+1) {}; Polynomial(const Polynomial& q):v(q.v) {}; Polynomial(T* const& ptr, const Degree& d):v(ptr,d+1) {}; Polynomial(const T& c, const_tag):v(1) {v[0] = c; setDegValue(0);} ~Polynomial(); /* manipulators */ T& operator[] (const Ulong& j) {return(v[j]);} T* ptr() {return v.ptr();} void reduceDeg() {v.reduceDim();} void setDeg(const Degree& d){v.setDim(d+1);} void setDegValue(const Degree& d){v.setDimValue(d+1);} void setVect(const T *source, Ulong n) {v.setVect(source,n);} void setZero(){v.dim() = 0;} void setZero(Ulong r){v.setZero(r);} void setZero(Ulong first, Ulong r){v.setZero(first,r);} Vector& vect() {return(v);} /* accessors */ const T& operator[] (const Ulong& j) const {return(v[j]);} Ulong deg() const {return v.dim()-1;} bool isZero() const {return (deg() == undef_degree);} const T* ptr() const {return v.ptr();} const Vector& vect() const {return(v);} /* operators and operations */ Polynomial& operator= (const Polynomial& q){v = q.v; return *this;} Polynomial& operator+= (const Polynomial& q); Polynomial& operator-= (const Polynomial& q); Polynomial& operator*= (const T& a); Polynomial& operator*= (const Polynomial& q); Polynomial& operator/= (const Polynomial& q); }; class Monomial { private: Degree n; public: Monomial(Degree d){n = d;}; }; template class LaurentPolynomial { protected: Polynomial d_pol; SDegree d_valuation; /* degree of first non-zero coefficient */ public: /* constructors and destructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(LaurentPolynomial));} LaurentPolynomial() {}; LaurentPolynomial(const SDegree& d, const SDegree& o = 0); ~LaurentPolynomial(); /* accessors */ const T& operator[] (const SDegree& j) const; /* inlined */ bool operator== (const LaurentPolynomial& p) const; bool operator!= (const LaurentPolynomial& p) const; /* inlined */ bool operator<= (const LaurentPolynomial& p) const; bool operator>= (const LaurentPolynomial& p) const; bool operator< (const LaurentPolynomial& p) const; /* inlined */ bool operator> (const LaurentPolynomial& p) const; /* inlined */ SDegree deg() const; /* inlined */ bool isZero() const; /* inlined */ SDegree val() const; /* inlined */ /* manipulators */ T& operator[] (const SDegree& j); /* inlined */ void adjustBounds(); void setBounds(const SDegree& n, const SDegree& m); void setDeg(const SDegree& n); void setDegValue(const SDegree& n); /* inlined */ void setVal(const SDegree& n); void setValValue(const SDegree& n); /* inlined */ void setZero(); /* inlined */ }; }; /******** inline definitions **************************************************/ namespace polynomials { template inline bool operator!= (const Polynomial& p, const Polynomial& q) {return !(p == q);} template inline bool operator< (const Polynomial& p, const Polynomial& q) {return !(p >= q);} template inline bool operator> (const Polynomial& p, const Polynomial& q) {return !(p <= q);} template inline const T& LaurentPolynomial::operator[] (const SDegree& j) const {return d_pol[j-d_valuation];} template inline T& LaurentPolynomial::operator[] (const SDegree& j) {return d_pol[j-d_valuation];} template inline bool LaurentPolynomial::operator!= (const LaurentPolynomial& p) const {return !operator== (p);} template inline bool LaurentPolynomial::operator> (const LaurentPolynomial& p) const {return !operator<= (p);} template inline bool LaurentPolynomial::operator< (const LaurentPolynomial& p) const {return !operator>= (p);} template inline SDegree LaurentPolynomial::deg() const {return d_pol.deg()+d_valuation;} template inline bool LaurentPolynomial::isZero() const {return d_pol.isZero();} template inline void LaurentPolynomial::setDegValue(const SDegree& n) {d_pol.setDegValue(n-d_valuation);} template inline void LaurentPolynomial::setValValue(const SDegree& n) {d_valuation = n;} template inline SDegree LaurentPolynomial::val() const {return d_valuation;} template inline void LaurentPolynomial::setZero() {d_pol.setZero();} }; #include "polynomials.hpp" #endif positivity_final/polynomials.hpp0000600000175000017500000004271710012724704020721 0ustar duclouxducloux00000000000000/* This is polynomials.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /**************************************************************************** This module defines the polynomials used in this program. A polynomial is in fact just a vector, suitably reinterpreted. The degree of the polynomial is the (reduced) dimension of the vector minus one; we always make sure that the degree is exactly right, i.e., it is undef_degree = -1 for the zero polynomial, and otherwise we have v[deg] != 0. ****************************************************************************/ /**************************************************************************** Chapter I --- The Polynomial class ****************************************************************************/ namespace polynomials { template Polynomial::~Polynomial() /* Destruction is automatic. */ {} /******** operators *********************************************************/ template Polynomial& Polynomial::operator+= (const Polynomial& q) /* Adds q to the current polynomial. */ { /* check for zero */ if (q.isZero()) /* do nothing */ return *this; if (isZero()) { /* set p to q */ *this = q; return *this; } v += q.v; v.reduceDim(); /* set the degree to the correct value */ return *this; } template Polynomial& Polynomial::operator-= (const Polynomial& q) /* Adds q to the current polynomial. */ { Degree j; /* check for zero */ if (q.isZero()) /* do nothing */ return *this; if (isZero()) { /* set p to -q */ *this = q; for (j = 0; j <= deg(); j++) v[j] = -v[j]; return *this; } v -= q.v; v.reduceDim(); /* set the degree to the correct value */ return *this; } template Polynomial& Polynomial::operator*= (const Polynomial& q) /* Multiplies the current polynomial by q. NOTE : we have used tmp as workspace for simplicity, although this can be eliminated altogether. */ { static Vector tmp; if ( isZero() || q.isZero() ) /* result is 0 */ { setDeg(undef_degree); return *this; } tmp.setDim(deg()+q.deg()+1); Degree i, j; for (i = 0; i <= deg(); i++) for (j = 0; j <= q.deg(); j++) tmp[i+j] += v[i]*q[j]; setDeg(deg()+q.deg()+1); v = tmp; return *this; } template Polynomial& Polynomial::operator*= (const T& a) /* Scalar multiplication by a. */ { if ( isZero() || (a == 0) /* should be isZero(a) */) /* result is 0 */ { setDeg(undef_degree); return *this; } v *= a; return *this; } template Polynomial& Polynomial::operator/= (const Polynomial& q) /* Euclidian division by q; we assume that the leading coefficient of q is one. It turns out that everything can be done within p's memory space (even when p = q!). */ { if (deg() < q.deg()) { /* result is 0 */ setDeg(undef_degree); return *this; } Degree i, j; for (j = deg()-q.deg()+1; j;) { j--; for (i = 0; i < q.deg(); i++) v[i+j] -= v[q.deg()+j]*q[i]; } v.setVect(v.ptr()+q.deg(),deg()-q.deg()+1); setDeg(deg()-q.deg()); return *this; } }; /***************************************************************************** Chapter II -- Comparison operators. This section defines comparison operators for polynomials, assuming that the corresponding comparison operators for type T have beeb defined. We define the following : - operator== (p,q); - operator!= (p,q); (inlined) - operator< (p,q); - operator> (p,q); ******************************************************************************/ namespace polynomials { template bool operator== (const Polynomial& p, const Polynomial& q) /* Equality operator for polynomials. Two polynomials are equal, if both are zero, or if their degrees are equal and the corresponding coefficients are equal. It is assumed that operator != is defined for T. */ { if (p.isZero()) return q.isZero(); if (p.deg() != q.deg()) return false; for (Ulong j = 0; j <= p.deg(); ++j) { if (p[j] != q[j]) return false; } return true; } template bool operator<= (const Polynomial& p, const Polynomial& q) /* We have p <= q if either p = 0, or deg(p) < deg(q), or degrees are equal and coefficients are in order, starting from the top. It is assumed that operator< is defined for T */ { if (p.deg() < q.deg()) return true; if (p.deg() > q.deg()) return false; /* now degrees are equal */ for (Ulong j = p.deg()+1; j;) { /* loop is empty if p = 0 */ --j; if (p[j] > q[j]) return false; if (p[j] < q[j]) return true; } /* now polynomials are equal */ return true; } template bool operator>= (const Polynomial& p, const Polynomial& q) /* We have p >= q if either deg(p) > deg(q), or degrees are equal and coefficients are in order, starting from the top. It is assumed that operator< is defined for T */ { if (p.deg() > q.deg()) return true; if (p.deg() < q.deg()) return false; /* now degrees are equal */ for (Ulong j = p.deg()+1; j;) { /* loop is empty if p = 0 */ --j; if (p[j] < q[j]) return false; if (p[j] > q[j]) return true; } /* now polynomials are equal */ return true; } }; /************************************************************************** Chapter III --- Input/output This section defines i/o functions for polynomials : - append(str,p,x) : appends the representation of p to the string l (also defined for Laurent polynomials); - append(str,p,d,m,x) : same, substituting X^d and shifting degrees by m; - append(str,p,d,m,x,GAP) : same as the previous one, in GAP style; - append(str,p,d,m,x,Terse) : same as the previous one, in Terse style; - print(file,p,x) : appends the representation of p to the file (also defined for Laurent polynomials); - print(str,p,d,m,x) : same, substituting X^d and shifting degrees by m; - print(str,p,d,m,x,GAP) : same as the previous one, in GAP style; - print(str,p,d,m,x,Terse) : same as the previous one, in Terse style; **************************************************************************/ namespace polynomials { template String& append(String& str, const Polynomial &p, const char *x) /* Appends the string representation of p to l, using the string x to represent the indeterminate. */ { if (p.isZero()) { io::append(str,"0"); return str; } int firstcoeff = 1; Degree j = p.deg()+1; while (j) { j--; if (p[j] == 0) continue; if (firstcoeff) firstcoeff = 0; else if (p[j] > 0) append(str,"+"); switch (j) { case 0: io::append(str,p[j]); break; default: if ((p[j] != 1) && (p[j] != (T)(-1))) io::append(str,p[j]); else if (p[j] == (T)(-1)) append(str,"-"); break; }; switch (j) { case 0: break; case 1: append(str,x); break; default: append(str,x); append(str,"^"); append(str,j); break; }; } return str; } template String& append(String& str, const LaurentPolynomial &p, const char *x) /* Appends the string representation of p to l, using the string x to represent the indeterminate. */ { if (p.isZero()) { io::append(str,"0"); return str; } int firstcoeff = 1; for (long j = p.val(); j <= p.deg(); ++j) { if (p[j] == 0) continue; if (firstcoeff) firstcoeff = 0; else if (p[j] > 0) append(str,"+"); switch (j) { case 0: append(str,p[j]); break; default: if ((p[j] != 1) && (p[j] != (T)(-1))) append(str,p[j]); else if (p[j] == (T)(-1)) append(str,"-"); break; }; switch (j) { case 0: break; case 1: append(str,x); break; default: append(str,x); append(str,"^"); append(str,j); break; }; } return str; } template String& append(String& str, const Polynomial &p, const Degree& d, const long& m, const char *x) /* Appends the string representation of p to str, using the string x to represent the indeterminate. In this version, X^d is first substituted in the polynomial, and afterwards the whole thing is shifted by m. */ { if (p.deg() == undef_degree) { io::append(str,"0"); return str; } int firstcoeff = 1; Degree j = p.deg()+1; while (j) { j--; if (p[j] == 0) continue; if (firstcoeff) firstcoeff = 0; else if (p[j] > 0) append(str,"+"); long a = j*d + m; switch (a) { case 0: append(str,p[j]); break; default: if ((p[j] != (T)1) && (p[j] != (T)(-1))) append(str,p[j]); else if (p[j] == (T)(-1)) append(str,"-"); break; }; switch (a) { case 0: break; case 1: append(str,x); break; default: append(str,x); append(str,"^"); append(str,a); break; }; } return str; } template String& append(String& str, const Polynomial &p, const Degree& d, const long& m, const char *x, GAP) /* Appends the GAP representation of p to str, using the string x to represent the indeterminate. In this version, X^d is first substituted in the polynomial, and afterwards the whole thing is shifted by m. The only difference with the ordinary print is that a * is required between then coefficient and the indeterminate. */ { if (p.deg() == undef_degree) { io::append(str,"0"); return str; } int firstcoeff = 1; Degree j = p.deg()+1; while (j) { j--; if (p[j] == 0) continue; if (firstcoeff) firstcoeff = 0; else if (p[j] > 0) append(str,"+"); long a = j*d + m; switch (a) { case 0: append(str,p[j]); break; default: if ((p[j] != (T)1) && (p[j] != (T)(-1))) { append(str,p[j]); append(str,"*"); } else if (p[j] == (T)(-1)) append(str,"-"); break; }; switch (a) { case 0: break; case 1: append(str,x); break; default: append(str,x); append(str,"^"); append(str,a); break; }; } return str; } template String& append(String& str, const Polynomial &p, const Degree& d, const long& m, const char *x, Terse) /* Appends the Terse representation of p to str, using the string x to represent the indeterminate. In this version, X^d is first substituted in the polynomial, and afterwards the whole thing is shifted by m. In terse style, polynomials are represented as comma-separated lists of coefficients, enclosed by parentheses. Whenever either d is different from one, or m is different from zero, the polynomial is preceded by a pair (d,m), also enclosed in parentheses. */ { if (p.deg() == undef_degree) { io::append(str,"()"); return str; } if ((d != 1) || (m != 0)) { io::append(str,"("); io::append(str,d); io::append(str,","); io::append(str,m); io::append(str,")"); } io::append(str,"("); for (Ulong j = 0; j <= p.deg(); ++j) { io::append(str,p[j]); if ((j+1) <= p.deg()) /* there is more to come */ io::append(str,","); } io::append(str,")"); return str; } template void print(FILE* file, const Polynomial& p, const char* x) { static String buf(0); reset(buf); append(buf,p,x); print(file,buf); return; } template void print(FILE* file, const LaurentPolynomial& p, const char* x) { static String buf(0); reset(buf); append(buf,p,x); print(file,buf); return; } template void print(FILE* file, const Polynomial& p, const Degree& d, const long& m, const char* x) /* Prints the polynomial with x^d substituted for x, and shifted by m (so that we may actually be printing a Laurent polynomial.) */ { static String buf(0); reset(buf); append(buf,p,d,m,x); print(file,buf); return; } template void print(FILE* file, const Polynomial& p, const Degree& d, const long& m, const char* x, GAP) /* Prints the polynomial with x^d substituted for x, and shifted by m (so that we may actually be printing a Laurent polynomial.) */ { static String buf(0); reset(buf); append(buf,p,d,m,x,GAP()); print(file,buf); return; } template void print(FILE* file, const Polynomial& p, const Degree& d, const long& m, const char* x, Terse) /* Prints the polynomial in terse style. */ { static String buf(0); reset(buf); append(buf,p,d,m,x,Terse()); print(file,buf); return; } /***************************************************************************** Chapter IV -- The LaurentPolynomial class The LaurentPolynomial class is just an adaptor for a polynomial; all operations are done at the level of an underlying polynomial, and there is just a shift to be taken into account. The degree (valuation) of a Laurent polynomial is the position of its largest (smallest) non-zero coefficient. The following functions are defined : - constructors and destructors : - LaurentPolynomial(const SDegree&, const SDegree&) : constructs a Laurent polynomial capable of holding the given degree and valuation; - ~LaurentPolynomial(); - accessors : - operator== (const LaurentPolynomial&); - operator<= (const LaurentPolynomial&); - operator>= (const LaurentPolynomial&); - manipulators : - adjustBounds() : makes sure degree and valuation answer to their definitions; - setBounds(const SDegree&, const SDegree&) : sets both the degree and the valuation, enlarging if necessary; - setDeg(const SDegree&) : sets the degree, enlarging if necessary; - setVal(const SDegree&) : sets the valuation, enlarging if necessary; The following comparison operators are defined : - operator== : equality of valuations and polynomials; - operator!= : the negation of ==; (inlined) - operator<= : inequality of valuations and of polynomials; (inlined) - operator>= : inequality of valuations and polynomials; (inlined) - operator< : negation of <=; (inlined) - operator> : negation of >=; (inlined) *****************************************************************************/ template LaurentPolynomial::LaurentPolynomial(const SDegree& d, const SDegree& o) :d_pol(d-o),d_valuation(o) /* Constructs a Laurent polynomial with capacity d-o+1. */ {} template LaurentPolynomial::~LaurentPolynomial() /* Automatic destruction is enough. */ {} /******** accessors *********************************************************/ template bool LaurentPolynomial::operator== (const LaurentPolynomial& p) const /* Comparison operator for Laurent polynomials. Two Laurent polynomials are equal if both are zero, or if the valuations are equal and the polynomials are equal. */ { if (isZero()) return p.isZero(); if (p.isZero()) return false; if (d_valuation != p.d_valuation) return false; return d_pol == p.d_pol; } template bool LaurentPolynomial::operator<= (const LaurentPolynomial& p) const /* Comparison operator for Laurent polynomials. Zero is larger than any polynomial; otherwise comparison is valuation-first. */ { if (p.isZero()) return true; if (isZero()) return false; if (d_valuation < p.d_valuation) return true; return d_pol <= p.d_pol; } template bool LaurentPolynomial::operator>= (const LaurentPolynomial& p) const /* Comparison operator for Laurent polynomials. Zero is larger than any polynomial; otherwise comparison is valuation-first. */ { if (isZero()) return true; if (p.isZero()) return false; if (d_valuation > p.d_valuation) return true; return d_pol >= p.d_pol; } /******** manipulators ******************************************************/ template void LaurentPolynomial::adjustBounds() /* Adjusts the degree and valuation so that they answer their definition, and makes sure that the degree of d_pol is exactly deg-val. Should be used after a lazy execution of an additive operation. */ { if (isZero()) return; Ulong a = 0; for (; a < d_pol.deg(); ++a) { if (d_pol[a]) break; } if (a) { /* valuation is wrong */ d_valuation += a; d_pol.setVect(d_pol.vect().ptr()+a,0); } d_pol.reduceDeg(); return; } template void LaurentPolynomial::setBounds(const SDegree& n, const SDegree& m) /* Sets both the degree and the valuation; safe to use even on a garbaged polynomial; NOTE : both the n-th and m-th coefficients should be nonzero! */ { d_pol.setDeg(n-m); d_valuation = m; return; } template void LaurentPolynomial::setDeg(const SDegree& n) /* This function sets the degree of the polynomial to n, making more room if necessary. NOTE : n-th coefficient should be non-zero! NOTE : is dangerous when used on a zero-polynomial. Use setBounds instead. */ { d_pol.setDeg(n-d_valuation); return; } template void LaurentPolynomial::setVal(const SDegree& n) /* This function sets the valuation of the polynomial to n, making more space if necessary. NOTE : n-th coefficient should be non-zero! NOTE : should not be used on a zero-polynomial. Use setBounds instead. */ { d_valuation = n; d_pol.setDeg(deg()-n); return; } }; positivity_final/posets.cpp0000600000175000017500000001262110011171251017642 0ustar duclouxducloux00000000000000/* This is posets.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "posets.h" /**************************************************************************** This file contains some code for the analysis of posets --- this would be a subject for a program per se! Currently the only "general" poset that appears in the program is the primitive ideal spectrum, i.e. the set of cells in a W-graph, considered as an ordered set. We just include some functions that are required to normalize and output this poset. ****************************************************************************/ namespace { using namespace posets; PosetElt firstMinimal(const OrientedGraph& G, const BitMap& b); } /**************************************************************************** Chapter I -- The Poset class The Poset class is just a straightforward implementation of a poset; the idea is that we will never have to deal with poseets that have more than a few thousand elements; therefore we can afford the luxury to carry the full incidence graph, as a list of BitMaps. This allows for very fast comparison testing, and efficient functions to analyze the poset. The following functions are provided : - constructors and destructors : - Poset(); - Poset(const Ulong&); - Poset(const OrientedGraph&); - ~Poset(); - manipulators : - accessors : - findMaximals(D,a) : writes the maximal elements of D in a; - hasseDiagram(H) : writes the Hasse diagram in H; - isTriangular() : checks if the poset is triangular; - size(); (inlined) ****************************************************************************/ namespace posets { Poset::Poset() {} Poset::Poset(const Ulong& n):d_closure(n) /* Constructs a Poset structure capable of accomodating a Poset of size n. */ { d_closure.setSizeValue(n); for (Ulong j = 0; j < n; ++j) { new(d_closure.ptr()+j) BitMap(n); } } Poset::Poset(const OrientedGraph& G):d_closure(G.size()) /* Constructs the poset defined by the graph G, assumed to be acyclic; i.e., the underlying set is the vertex set of G, and x <= y iff there is an oriented path in G from y to x (we assume that G describes dominance relations, as a matter of convention.) */ { static BitMap b(0); d_closure.setSizeValue(G.size()); for (Ulong j = 0; j < size(); ++j) { new(d_closure.ptr()+j) BitMap(size()); } /* set the bitmaps */ b.setSize(size()); b.reset(); for (Ulong j = 0; j < size(); ++j) { PosetElt x = firstMinimal(G,b); b.setBit(x); const EdgeList& e = G.edge(x); d_closure[x].setBit(x); for (Ulong i = 0; i < e.size(); ++i) { d_closure[x] |= d_closure[e[i]]; } } } Poset::~Poset() /* Automatic destruction of the components is enough. */ {} /******** manipulators ******************************************************/ /******** accessors *********************************************************/ void Poset::findMaximals(const BitMap& D, Set& a) const /* This function writes in a the maximal elements of D. It assumes that the poset is in triangular form. The algorithm is as follows. The largest element z in D is certainly maximal. Then remove cl(z) from D, and iterate until reaching the empty set. */ { static BitMap b(0); b.assign(D); for (PosetElt x = b.lastBit(); x < b.size(); x = b.lastBit()) { insert(a,x); b.andnot(d_closure[x]); } } bool Poset::isTriangular() const /* This function checks whether the poset is enumerated in a way compatible with the ordering, viz. s.t. x <= y in the poset implies x <= y as numbers. If not, it is always possible to permute the poset in order to get such an enumeration. */ { for (PosetElt x = 0; x < size(); ++x) { if (!d_closure[x].isEmpty(x+1)) return false; } return true; } void Poset::hasseDiagram(OrientedGraph& H) /* This function returns in H the Hasse diagram of the poset, i.e. for each y the elements x which lie immediately under y. */ { H.setSize(size()); for (PosetElt x = 0; x < size(); ++x) { d_closure[x].clearBit(x); findMaximals(d_closure[x],H.edge(x)); d_closure[x].setBit(x); } } /******** input/output ******************************************************/ }; /***************************************************************************** Chapter II -- Auxiliary functions. This chapter defines some auxiliary functions used in this module : - firstMinimal(G,b) : return the first x in G minimal in the complement of b; *****************************************************************************/ namespace { PosetElt firstMinimal(const OrientedGraph& G, const BitMap& b) /* This function is an auxiliary to Poset(G). Given a bitmap b, which is assumed to hold a certain subset of the vertex set of G, it returns the first element x in G which is not in b, but all the edges of which go to elements in b. Returns the value G.size() if no such element is found, which should happen iff b holds the full set. */ { Ulong x = 0; for (; x < G.size(); ++x) { if (b.getBit(x)) continue; const EdgeList& e = G.edge(x); for (Ulong i = 0; i < e.size(); ++i) { if (!b.getBit(e[i])) goto nextx; } /* if we reach this point our element is found */ break; nextx: continue; } return x; } }; positivity_final/posets.h0000600000175000017500000000246410011171251017313 0ustar duclouxducloux00000000000000/* This is posets.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef POSETS_H /* guard against multiple inclusions */ #define POSETS_H #include "globals.h" namespace posets { using namespace globals; }; /******** type declarations *************************************************/ namespace posets { typedef Ulong PosetElt; class Poset; }; /******** type definitions **************************************************/ #include "bits.h" #include "list.h" #include "memory.h" #include "wgraph.h" namespace posets { using namespace bits; using namespace list; using namespace wgraph; }; namespace posets { class Poset { List d_closure; public: /* constructors and destructors */ void operator delete(void* ptr, size_t size) {return arena().free(ptr,sizeof(Poset));} Poset(); Poset(const Ulong &n); Poset(const OrientedGraph& G); ~Poset(); /* manipulators */ /* accessors */ void findMaximals(const BitMap& D, Set& a) const; bool isTriangular() const; Ulong size() const; void hasseDiagram(OrientedGraph& H); /* input/output */ }; }; /******** inline implementations ********************************************/ namespace posets { inline Ulong Poset::size() const {return d_closure.size();} }; #endif positivity_final/schubert.cpp0000600000175000017500000013576410014463536020177 0ustar duclouxducloux00000000000000/* This is schubert.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "schubert.h" #include "error.h" namespace schubert { using namespace error; }; /**************************************************************************** This file contains the definition of the general functions pertaining to Schubert contexts, and the definition of the StandardSchubertContext class. Other implementations of Schubert contexts will be found in other files. A Schubert context contains a description of a finite decreasing subset Q of the group (initially the singleton {e}), and should be capable of providing data and services related to the Bruhat ordering and to the (partially defined) action of the generators on the Q. The elements of Q are assumed to be enumerated by the integers in the range [0,size()[, in an ordering compatible with the Bruhat ordering. Specifically, the following functions are required : - managing the context : - append(g,x) : appends to the CoxWord g a reduced expression of the element #x in Q; - contextNumber(g) : returns the number x in [0,size()[ corresponding to the CoxWord g, or undef_coxnbr if there is no such x; - descent sets : - descent(x) : returns the two-sided descent set of x, flagged in a LFlags; - ldescent(x), rdescent(x) : same for left (right) descent sets; - firstDescent(x), firstLDescent(); firstRDescent(x) : returns the first set bit in the corresponding descent sets; - downset(s) : a bitmap of the set of x s.t. xs < x; - isDescent(x,s) : tells if s is a descent for x; - maximize(x,f), minimize(x,f) : extremalizes x w.r.t. the action of the generators flagged by f; - Bruhat ordering : - extendSubSet(q,s) : given q holding a decreasing subset of Q, and s s.t. q.s is contained in Q, puts q.s in q; - extractClosure(q,x) : puts in q the interval [e,x]; - hasse(x) : returns the coatom list of x; - inOrder(x,y) : tells if x <= y; - action of generators : - shift(x,s) : returns the shift xs (left shift by s-rank() if s > rank()); - lshift(x,s), rshift(x,s) : left or right shifts; - length : - length(x) : returns the length of element #x; - maxlength() : largest length of element in context; - parity(x) : a bitmap of the set of z s.t. length(z) = length(x) mod 2; - sizes : - rank() : returns the rank of the underlying group; - setSize(n) : this should really be a private function; it can be used safely only in order to _reduce_ the size of the context (typically, when the Schubert extension succeeded but the kl extension failed, and we wish to revert;) - size() : returns the current size of the context; The StandardSchubertContext class contains lengths, shifts, coatoms and downsets as tables, so the above functions are really simply table accesses. The context extension and interval extraction is done as described in my paper "Computing Kazhdan-Lusztig polynomials for arbitrary Coxeter groups", Experiment. Math. 11 (2002), no. 3, pp. 371-381. ****************************************************************************/ namespace { using namespace schubert; using namespace bits; const char* undef_str = "undefined"; void resetOne(SubSet& q); }; /**************************************************************************** Chapter I -- The StandardSchubertContext class. This section defines the functions in the SchubertContext class : - constructors and destructors : - StandardSchubertContext(G); - ~StandardSchubertContext - accessors : - append(g,x) : appends the normal form of x to g; - closure(x) : returns a bitmap of the interval [e,x]; - contextNumber(g) : returns the number of g in the context; - descent(x), ldescent(x), rdescent(x) : descent sets; (inlined) - downset(s) : bitmap of {x, xs < x}; (inlined) - firstDescent(x), firstLDescent(x), firstRDescent(x) : smallest generator taking x down; (inlined) - hasse(x) : the list of coatoms of x; (inlined) - inOrder(x,y) : tells if x <= y; - length (x) : the length of x; (inlined) - maximize(x,f) : maximizes x w.r.t. the action of the generators in f; - maxlength() : maximal length in context; (inlined) - minimize(x,f) : minimizes x w.r.t. the action of the generators in f; - normalForm(g,x,order) : returns the normal form of x for order; - parity(x) : bitmap of {z, l(z)=l(x) mod 2}; (inlined) - rank() : the rank of the group; (inlined) - shift(x,s), lshift(x,s), rshift(x,s) : shifts x by s; (inlined) - size() : the size of the context; (inlined) - twoDescent(y) : returns the "super-descent" set of y; - modifiers : - extendContext(g) : extends the context to accomodate g; - extendSubSet(s) : extends the subset to accomodate multiplication by s; - permute(q) : applies the permutation q to the context; - revertSize(n) : reverts to a previous size; - setSize(n) : resets the size; - subset() : gives access to the subset; (inlined) ****************************************************************************/ namespace schubert { /******** constructors ******************************************************/ StandardSchubertContext::StandardSchubertContext(const CoxGraph& G) :d_graph(G), d_rank(G.rank()), d_maxlength(0), d_size(1), d_length(1), d_hasse(1), d_descent(1), d_shift(1), d_star(1), d_subset(1) /* Constructor for the SchubertContext class. The data are initialized for the one-element context {e} : size is one, and for the single element 0, length is 0, descent sets are empty, coatom set is empty, shifts are all undefined. */ { d_length.setSizeValue(1); d_hasse.setSizeValue(1); d_descent.setSizeValue(1); d_shift.setSizeValue(1); d_star.setSizeValue(1); d_shift[0] = new(arena()) CoxNbr[2*rank()]; for (Ulong j = 0; j < 2*static_cast(d_rank); ++j) d_shift[0][j] = undef_coxnbr; d_star[0] = new(arena()) CoxNbr[2*nStarOps()]; for (StarOp j = 0; j < 2*nStarOps(); ++j) d_star[0][j] = undef_coxnbr; d_downset = new(arena()) BitMap[2*d_rank]; for (Ulong j = 0; j < 2*static_cast(d_rank); ++j) new(d_downset+j) BitMap(1); d_parity = new(arena()) BitMap[2]; new(d_parity) BitMap(1); new(d_parity+1) BitMap(1); d_parity[0].setBit(0); } StandardSchubertContext::~StandardSchubertContext() /* Destructing a SchubertContext turns out to be a little bit tricky, because of the way memory has been allocated for the various structures, in the successive extensions. In particular, in d_shift and d_star, only *some* pointers have been allocated by new. This problem will be much easier to handle once the memory allocations go through a private arena; it will then be enough to simply free the arena. For now, we introduce a monitoring through a stack of ContextExtensions. Apart from this, the only thing that has to be deleted directly is downset. */ { /* reverse history */ while (d_history.size()) { delete *d_history.pop(); } for (Ulong j = 0; j < 2*static_cast(d_rank); ++j) { d_downset[j].~BitMap(); } d_parity[0].~BitMap(); d_parity[1].~BitMap(); arena().free(d_star[0],2*nStarOps()*sizeof(CoxNbr)); arena().free(d_shift[0],2*rank()*sizeof(CoxNbr)); } /******** accessors ********************************************************/ CoxWord& StandardSchubertContext::append(CoxWord& g, const CoxNbr& d_x) const /* This function appends to g the ShortLex normal form of x. The normal form is easily obtained using the left descent sets. NOTE : it is the progarmmer's responsibilty when using this function, to guarantee that the result is reduced. Otherwise, use "prod". */ { CoxNbr x = d_x; while (x) { Generator s = firstBit(ldescent(x)); g.append(s+1); x = lshift(x,s); } return g; } CoxNbr StandardSchubertContext::contextNumber(const CoxWord& g) const /* This functions returns the number corresponding to g in the current context; returns undef_coxnbr if g is not in the context. */ { CoxNbr x = 0; for (Ulong j = 0; j < g.length(); ++j) { Generator s = g[j]-1; x = rshift(x,s); if (x == undef_coxnbr) break; } return x; } void StandardSchubertContext::extractClosure(BitMap& b, const CoxNbr& x) const /* This function puts in b the subset [e,x] of p. It is assumed that b is capable of holding a subset of p. Forwards the error MEMORY_WARNING if CATCH_MEMORY_OVERFLOW is set. */ { SubSet q(d_size); resetOne(q); for (CoxNbr x1 = x; x1;) { Generator s = firstLDescent(x1); extendSubSet(q,s); x1 = d_shift[x1][s+d_rank]; } b = q.bitMap(); return; } bool StandardSchubertContext::inOrder(CoxNbr x, CoxNbr y) const /* Checks if x <= y in the Bruhat ordering, using the well-known recursive algorithm : if y = 0, then x must be 0; otherwise, take s s.t. ys < y; then if xs < x, x <= y iff xs < ys; if xs > x, x <= y iff x <= ys. NOTE : this function is not intended for heavy use! */ { if (x == 0) return true; if (x == y) return true; if (x > y) return false; Generator s = firstDescent(y); CoxNbr xs = d_shift[x][s]; CoxNbr ys = d_shift[y][s]; if (xs < x) return inOrder(xs,ys); else /* xs > x */ return inOrder(x,ys); } CoxNbr StandardSchubertContext::maximize(const CoxNbr& x, const LFlags& f) const /* This function maximizes x w.r.t. the flags in f. The return value is undef_coxnbr if the extremalization takes us outside the context. It is assumed that f is a valid set of flags, i.e., contained in S \coprod S. */ { CoxNbr x1 = x; LFlags g = f & ~d_descent[x1]; while (g) { Generator s = firstBit(g); x1 = d_shift[x1][s]; if (x1 == undef_coxnbr) break; g = f & ~d_descent[x1]; } return x1; } CoxNbr StandardSchubertContext::minimize(const CoxNbr& x, const LFlags& f) const /* This function minimizes x w.r.t. the flags in f. Here the return value is always defined. It is assumed that f is a valid set of flags, i.e., contained in S \coprod S. */ { CoxNbr x1 = x; LFlags g = f & d_descent[x1]; while (g) { Generator s = firstBit(g); x1 = d_shift[x1][s]; g = f & d_descent[x1]; } return x1; } CoxWord& StandardSchubertContext::normalForm(CoxWord& g, const CoxNbr& d_x, const Permutation& order) const /* This function returns the normal form of x for the given ordering of the generators. The order parameter is typically d_out in interface; so order[j] is the external number of the internal generator #j. NOTE : this function is more expensive than append; its main intention is for use in i/o functions. */ { g.reset(); CoxNbr x = d_x; while (x) { Generator s = minDescent(ldescent(x),order); g.append(s+1); x = lshift(x,s); } return g; } LFlags StandardSchubertContext::twoDescent(const CoxNbr& x) const /* Returns the "super-descent" set of x; this is the union of the descent set of x, and of the descent sets of the xs, where s runs through the descent set of x. */ { LFlags f = descent(x); for (LFlags f1 = f; f1; f1 &= f1-1) { Generator s = firstBit(f1); CoxNbr xs = shift(x,s); f |= descent(xs); } return f; } /******** modifiers ********************************************************/ CoxNbr StandardSchubertContext::extendContext(const CoxWord& g) /* This function extends the context to the smallest one containing the exixting one and the given g, i.e., the new context is the union of the old context and [e,g]. Apart from some previously undefined shifts becoming defined, this doesn't induce _any_ modification in the data for the old context; the numbers of the new elements come in at the top. Sets the error ... in case of failure. The outline of the function is as follows. First, we determine the largest subword h of g which is alreaady in the context, and construct the interval [e,h] as a subset of the context. Then, for each remaining generator in g, we add the elements in [e,hs] not already in the context, and we update everything. */ { CoxNbr y = 0; SubSet& q = d_subset; resetOne(q); Ulong j = 0; CATCH_MEMORY_OVERFLOW = true; for (; j < g.length(); ++j) { Generator s = g[j]-1; if (rshift(y,s) == undef_coxnbr) break; extendSubSet(q,s); if (ERRNO) goto error_handling; y = rshift(y,s); } for (; j < g.length(); ++j) { Generator s = g[j]-1; fullExtension(q,s); if (ERRNO) goto error_handling; if (j >= d_maxlength) d_maxlength = j+1; y = rshift(y,s); } CATCH_MEMORY_OVERFLOW = false; return y; error_handling: Error(ERRNO); ERRNO = EXTENSION_FAIL; return(undef_coxnbr); } void StandardSchubertContext::extendSubSet(SubSet& q, const Generator& s) const /* Given a subset q of p holding a decreasing subset, and a geneator s s.t. q.s. is contained in the context, in the context, this function puts in q the set q.s ( here s can be either a right or a left shift.) Forwards the error MEMORY_WARNING if CATCH_MEMORY_OVERFLOW is set. */ { Ulong a = q.size(); for (Ulong j = 0; j < a; ++j) { /* run through q */ CoxNbr x = (CoxNbr)q[j]; CoxNbr xs = d_shift[x][s]; if (xs < x) continue; if (q.isMember(xs)) continue; /* if we get here a new element is found */ q.add(xs); if (ERRNO) return; } return; } void StandardSchubertContext::permute(const Permutation& a) /* This function applies the permutation a to the context. We have explained in kl.cpp how this should be done. The objects to be permuted are the following : - d_length : a table with range in the context; - d_hasse : each row is a list with values in the context; the table itself has range in the context; in addition the permuted rows should be sorted; - d_descent : a table with range in the context; - d_shift : a table with range in the context; each row has values in the context, or undef_coxnbr; - d_downset : a table of bitmaps ranging over the context; - d_parity : a pair of bitmaps ranging over the context; */ { static BitMap b(0); static CoatomList hasse_buf; /* quick fix; can go when all lists are pointer lists */ /* permute values */ for (CoxNbr x = 0; x < d_size; ++x) { CoatomList& c = d_hasse[x]; for (Ulong j = 0; j < c.size(); ++j) c[j] = a[c[j]]; c.sort(); } for (CoxNbr x = 0; x < d_size; ++x) { for (Generator s = 0; s < 2*d_rank; ++s) { if (d_shift[x][s] != undef_coxnbr) d_shift[x][s] = a[d_shift[x][s]]; } } /* permute the ranges */ b.setSize(a.size()); b.reset(); for (CoxNbr x = 0; x < this->size(); ++x) { if (b.getBit(x)) continue; if (a[x] == x) { b.setBit(x); continue; } for (CoxNbr y = a[x]; y != x; y = a[y]) { /* back up values for y */ Length length_buf = d_length[y]; hasse_buf.shallowCopy(d_hasse[y]); LFlags descent_buf = d_descent[y]; CoxNbr* shift_buf = d_shift[y]; /* put values for x in y */ d_length[y] = d_length[x]; d_hasse[y].shallowCopy(d_hasse[x]); d_descent[y] = d_descent[x]; d_shift[y] = d_shift[x]; /* store backup values in x */ d_length[x] = length_buf; d_hasse[x].shallowCopy(hasse_buf); d_descent[x] = descent_buf; d_shift[x] = shift_buf; /* modify downsets */ for (Generator s = 0; s < 2*this->rank(); ++s) { bool t = d_downset[s].getBit(y); d_downset[s].setBit(y,d_downset[s].getBit(x)); d_downset[s].setBit(x,t); } /* modify parity bitmaps */ bool t = d_parity[0].getBit(y); d_parity[0].setBit(y,d_parity[0].getBit(x)); d_parity[0].setBit(x,t); t = d_parity[1].getBit(y); d_parity[1].setBit(y,d_parity[1].getBit(x)); d_parity[1].setBit(x,t); /* set bit*/ b.setBit(y); } b.setBit(x); } } void StandardSchubertContext::revertSize(const Ulong& n) /* This function reverts the size of the context to some previous value. It is very important that n is indeed a previous value of the context size (i.e. that it can be found through the extension history), and that no permutation has taken place between that previous size and the current size. This function is intended to be used immediately after the extension of the rest of the context failed, so that everything returns to where it was before. Because of the way things are allocated, we are actually able to return most of the allocated memory (only the allocations for the basic lists will remain as they were.) */ { Ulong m = size(); while (m > n) { ContextExtension* h = *d_history.pop(); m -= h->size(); delete h; } return; } void StandardSchubertContext::setSize(const Ulong& n) /* Resizes the various data structures to accomodate a context of size n. This means that the Lists d_length, d_hasse, d_descent and d_shift are resized to size n, and that memory is allocated for the new shift tables; we cannot do this for coatom lists, since they are variable in size. It is assumed that n is greater than the current size. Sets the error MEMORY_WARNING in case of overflow, if CATCH_MEMORY_OVERFLOW had been set. */ { Ulong prev_size = size(); CATCH_MEMORY_OVERFLOW = true; ContextExtension* e = new ContextExtension(*this,n-size()); if (ERRNO) /* extension failed */ goto revert; d_history.push(e); CATCH_MEMORY_OVERFLOW = false; return; revert: CATCH_MEMORY_OVERFLOW = false; revertSize(prev_size); return; } /******** input/output ****************************************************/ String& StandardSchubertContext::append(String& str, const CoxNbr& x) const { if (x == undef_coxnbr) io::append(str,undef_str); else coxtypes::append(str,x); return str; } String& StandardSchubertContext::append(String& str, const CoxNbr& x, const Interface& I) const { if (x == undef_coxnbr) return io::append(str,undef_str); else { CoxWord g(0); normalForm(g,x,I.order()); return I.append(str,g); } } void StandardSchubertContext::print(FILE* file, const CoxNbr& x) const { if (x == undef_coxnbr) fprintf(file,"%s",undef_str); else fprintf(file,"%lu",static_cast(x)); return; } void StandardSchubertContext::print(FILE* file, const CoxNbr& x, const Interface& I) const { if (x == undef_coxnbr) fprintf(file,"%s",undef_str); else { CoxWord g(0); normalForm(g,x,I.order()); I.print(file,g); } return; } /******** private member functions ****************************************** The following functions are defined as private member functions. The main reason for this is that this gives access to the representation, so that we can inline the access (to the shift table for instance) that would otherwise go to a virtual function call. - fillCoatoms(first,s) : fills in the coatom lists of new elements of the extension by s; - fillDihedralShifts(x,s) : fills in the shifts in the case where x is dihedral; - fillShifts(first,s) : fills in the shift tables of new elements of the extension by s; - fillStar(first) : fills in the star tables of new elements; - fullExtension(q,s) : fills in the extension obtained by adding the elements xs, x in q; *****************************************************************************/ void StandardSchubertContext::fillCoatoms(const Ulong& first, const Generator& s) /* This auxiliary fills the coatom lists of the new elements in p. It is assumed that p has been resized to the correct size, that first is the first new element, that lengths and shifts by s have been filled in. */ { static List c(1); for (CoxNbr x = first; x < d_size; ++x) { /* put coatom list in c */ CoxNbr xs = d_shift[x][s]; c.setSize(0); c.append(xs); CoatomList& cs = d_hasse[xs]; for (Ulong j = 0; j < cs.size(); ++j) { CoxNbr z = cs[j]; CoxNbr zs = d_shift[z][s]; if (zs > z) /* z moves up */ insert(c,zs); } /* copy to d_hasse[x] */ d_hasse[x].assign(c); } return; } void StandardSchubertContext::fillDihedralShifts(const CoxNbr& x, const Generator& s) /* This function fills in the shifts for x in the dihedral case. It is assumed that the shift by s is already filled in, and that length(x) is > 1. We have denoted on the right the action of s, on the left the action on the side different from s. This works even if in fact the action of s is on the left. */ { CoxNbr xs = d_shift[x][s]; /* find the other generator involved, on the same side as s */ Generator s1, t, t1; CoxEntry m; if (s < d_rank) { /* action is on the right */ t = firstRDescent(xs); s1 = s + d_rank; t1 = t + d_rank; m = d_graph.M(s,t); } else { /* action is on the left */ s1 = s - d_rank; t1 = firstLDescent(xs); t = t1 + d_rank; m = d_graph.M(s1,t1); } const CoatomList& c = d_hasse[x]; CoxNbr z; /* the other coatom of x */ if (c[0] == xs) z = c[1]; else z = c[0]; if (d_length[x] == m) { /* descents for s,t on both sides */ d_descent[x] |= lmask[t] | lmask[s1] | lmask[t1]; d_downset[t].setBit(x); d_downset[s1].setBit(x); d_downset[t1].setBit(x); d_shift[x][t] = z; d_shift[z][t] = x; if (m % 2) { /* xs = tx; xt = sx */ d_shift[x][s1] = z; d_shift[z][s1] = x; d_shift[x][t1] = xs; d_shift[xs][t1] = x; } else { /* xs = sx; xt = tx */ d_shift[x][s1] = xs; d_shift[xs][s1] = x; d_shift[x][t1] = z; d_shift[z][t1] = x; } } else { /* descent on one side only */ if (d_length[x] % 2) { /* xs and sx */ d_shift[x][s1] = z; d_shift[z][s1] = x; d_descent[x] |= lmask[s1]; d_downset[s1].setBit(x); } else { /* xs and tx */ d_shift[x][t1] = z; d_shift[z][t1] = x; d_descent[x] |= lmask[t1]; d_downset[t1].setBit(x); } } return; } void StandardSchubertContext::fillShifts(const CoxNbr& first, const Generator& s) /* This function fills in the shift tables of the new elements in p. It is assumed that first is the first new element, that the coatom tables, lengths and shifts by s have already been filled in. We use the algorithm deduced form Dyer's theorem, alluded to in the introduction. */ { CoxNbr x = first; /* check if something happens in length one; if there is a new element of length one, it is unique and equal to s */ if (d_length[x] == 1) { /* x = s */ Generator t; if (s < d_rank) /* s acts on the right */ t = s + d_rank; else /* s acts on the left */ t = s - d_rank; d_shift[0][t] = x; d_shift[x][t] = 0; d_descent[x] |= lmask[t]; d_downset[t].setBit(x); ++x; } for (; x < d_size; ++x) { const CoatomList& c = d_hasse[x]; if (c.size() == 2) { /* dihedral case */ fillDihedralShifts(x,s); continue; } for (Generator t = 0; t < 2*d_rank; ++t) { /* examine shift by t */ if (t == s) continue; bool firstplus = true; CoxNbr z = undef_coxnbr; for (Ulong j = 0; j < c.size(); ++j) { if (!(lmask[t] & d_descent[c[j]])) { /* coatom has ascent */ if (firstplus) { /* it's the first time */ firstplus = false; z = c[j]; // z is the coatom that goes up } else { goto nextt; } } } /* if we reach this point there was exactly one ascent */ d_shift[x][t] = z; d_shift[z][t] = x; d_descent[x] |= lmask[t]; d_downset[t].setBit(x); nextt: continue; } } return; } void StandardSchubertContext::fillStar(const CoxNbr& first) /* This function fills in the star operations for the new elements. Each star operation is a partially defined involution. The tables have already been initially set to undef_coxnbr; we fill in the operation in pairs, using the element that goes down. Recall that a star operation is associated to each edge {s,t} in the Coxeter graph such that m(s,t) < infty. The domain of the left star operation is the set of elements for which ldescent() intersects {s,t} in one element exactly (in other words, the elements that are neither minimal nor maximal in the left coset under the dihedral subgroup generated by s and t.) NOTE : a value undef_coxnbr means that either the element is not in the domain of the star operation, or that the star operation takes us out of context; hence an undefined value may become defined after extension; but this will always happen for elements paired up with a new element, so we only have to go through the new ones. */ { const List& ops = d_graph.starOps(); for (CoxNbr x = first; x < d_size; ++x) { LFlags fx = rdescent(x); for (StarOp j = 0; j < nStarOps(); ++j) { /* determine if x is in right domain */ LFlags f = fx & ops[j]; if ((f == 0) || (f == ops[j])) continue; CoxNbr x_min = minimize(x,ops[j]); Length d = d_length[x] - d_length[x_min]; Generator s = firstBit(f); /* the _only_ bit in f, actually */ Generator t = firstBit(ops[j] & ~f); CoxEntry m = d_graph.M(s,t); if (2*d < m) /* star is either undef_coxnbr or increasing */ continue; /* if we get here we fill in a pair in d_star */ if (2*d == m) d_star[x][j] = x; else { CoxNbr x1 = x; while ((d_length[x1] - d_length[x_min]) > (m - d)) { LFlags f1 = rdescent(x1) & ops[j]; Generator s1 = firstBit(f1); x1 = d_shift[x1][s1]; } d_star[x][j] = x1; d_star[x1][j] = x; } } fx = ldescent(x); for (StarOp j = 0; j < nStarOps(); ++j) { /* determine if x is in left domain */ LFlags f = fx & ops[j]; if ((f == 0) || (f == ops[j])) continue; LFlags lops = ops[j] << d_rank; CoxNbr x_min = minimize(x,lops); Length d = d_length[x] - d_length[x_min]; Generator s = firstBit(f); /* the _only_ bit in f, actually */ Generator t = firstBit(ops[j] & ~f); CoxEntry m = d_graph.M(s,t); if (2*d < m) /* star is either undef_coxnbr or increasing */ continue; /* if we get here we fill in a pair in d_star */ if (2*d == m) d_star[x][j+nStarOps()] = x; else { CoxNbr x1 = x; while ((d_length[x1] - d_length[x_min]) > (m - d)) { LFlags f1 = ldescent(x1) & ops[j]; Generator s1 = firstBit(f1); x1 = d_shift[x1][s1+d_rank]; } d_star[x][j+nStarOps()] = x1; d_star[x1][j+nStarOps()] = x; } } } return; } void StandardSchubertContext::fullExtension(SubSet& q, const Generator& s) /* Given a context p, a subset q of p holding [e,y], and a generator s s.t. y.s is not contained in p, this function extends p to hold y, and puts in q the interval [e,y.s] (here s can be either a right or a left shift.) Sets the following errors : - LENGHT_OVERFLOW if the new element has length greater than LENGTH_MAX (presumably this could have been checked before.) - COXNBR_OVERFLOW if the size of the extension would be greater than COXNBR_MAX; A more delicate problem is the handling of memory overflow. It has to be assumed that fullExtension labours under the constraint that CATCH_MEMORY_OVERFLOW is set; i.e., we don't want to exit brutally if we get a memory overflow, losing all previous computations. If an overflow error occurs, it is guaranteed that the context stays in its original form (except for sizes of varlists.) */ { /* check length overflow */ CoxNbr y = q[q.size()-1]; /* largest element in q */ if (d_length[y] == LENGTH_MAX) { /* overflow */ ERRNO = LENGTH_OVERFLOW; return; } /* determine the size of the extension */ CoxNbr c = 0; for (Ulong j = 0; j < q.size(); ++j) { /* run through q */ if (d_shift[q[j]][s] == undef_coxnbr) ++c; } /* check for size overflow */ if (c > COXNBR_MAX - d_size) { /* overflow */ ERRNO = COXNBR_OVERFLOW; return; } /* resize context */ CoxNbr prev_size = d_size; setSize(d_size+c); if (ERRNO) /* memory overflow */ goto revert; /* fill in lengths and shifts by s */ { CoxNbr xs = prev_size; /* first new element */ for (Ulong j = 0; j < q.size(); ++j) { CoxNbr x = q[j]; if (d_shift[x][s] == undef_coxnbr) { d_shift[x][s] = xs; d_shift[xs][s] = x; d_length[xs] = d_length[x] + 1; d_parity[d_length[xs]%2].setBit(xs); d_descent[xs] |= lmask[s]; d_downset[s].setBit(xs); xs++; } } /* fill in the new elements */ fillCoatoms(prev_size,s); fillShifts(prev_size,s); fillStar(prev_size); /* update q */ extendSubSet(q,s); if (ERRNO) goto revert; } return; revert: setSize(prev_size); return; } }; /**************************************************************************** Chapter II -- The ContextExtension class. The ContextExtension class is provided to manage the resizings of the context, so that we can keep track of the pointers that are allocated to new memory. The following functions are provided : - ContextExtension(p,c) : builds the extension; - ~ContextExtension(); NOTE : with reasonably managed arenas, this could probably be dropped; memory allocation in small chunks could be almost as fast and efficient as in big ones. ****************************************************************************/ namespace schubert { StandardSchubertContext::ContextExtension::ContextExtension (StandardSchubertContext& p, const Ulong& c) :d_schubert(p),d_size(c) /* This function manages the resizing of the SchubertContext p from its current size to size+c. */ { if (c == 0) return; Ulong n = p.size()+c; p.d_length.setSize(n); if (ERRNO) goto revert; p.d_hasse.setSize(n); if (ERRNO) goto revert; p.d_descent.setSize(n); if (ERRNO) goto revert; p.d_shift.setSize(n); if (ERRNO) goto revert; p.d_star.setSize(n); if (ERRNO) goto revert; /* make room for shift tables and star tables */ d_shift = new(arena()) CoxNbr[2*p.rank()*c]; if (ERRNO) goto revert; memset(d_shift,0xFF,2*p.rank()*c*sizeof(CoxNbr)); p.d_shift[p.d_size] = d_shift; for (Ulong j = p.d_size+1; j < n; ++j) p.d_shift[j] = p.d_shift[j-1] + 2*p.rank(); d_star = new(arena()) CoxNbr[2*p.nStarOps()*c]; if (ERRNO) goto revert; memset(d_star,0xFF,2*p.nStarOps()*c*sizeof(CoxNbr)); p.d_star[p.d_size] = d_star; for (Ulong j = p.d_size+1; j < n; ++j) p.d_star[j] = p.d_star[j-1] + 2*p.nStarOps(); for (Ulong j = 0; j < 2*static_cast(p.rank()); ++j) { p.d_downset[j].setSize(n); if (ERRNO) goto revert; } p.d_parity[0].setSize(n); p.d_parity[1].setSize(n); p.d_subset.setBitMapSize(n); if (ERRNO) goto revert; p.d_size = n; return; revert: p.d_length.setSize(p.d_size); p.d_hasse.setSize(p.d_size); p.d_descent.setSize(p.d_size); p.d_shift.setSize(p.d_size); for (Ulong j = 0; j < 2*static_cast(p.rank()); ++j) { p.d_downset[j].setSize(p.d_size); } p.d_parity[0].setSize(p.d_size); p.d_parity[1].setSize(p.d_size); return; } StandardSchubertContext::ContextExtension::~ContextExtension() /* Destruction of a context extension. NOTE : this is currently unfinished, and usable only for the destruction of a whole context. It should resize the lists downwards, and put undef_coxnbr values where appropriate (this can be determined by running through the deleted elements.) Also, it could take care of freeing the superfluous coatom lists. */ { StandardSchubertContext& p = d_schubert; Ulong prev_size = p.d_size-d_size; /* the pointers d_shift and d_star were allocated previously */ arena().free(d_shift,2*p.rank()*d_size*sizeof(CoxNbr)); arena().free(d_star,2*p.nStarOps()*d_size*sizeof(CoxNbr)); p.d_size = prev_size; return; } }; /**************************************************************************** Chapter II -- The ClosureIterator class. The closureIterator class is an iterator designed to loop over the context, providing at each step a SubSet holding the closure of element #y. This sort of loop will be needed in constructing tables of kl polynomials and mu-coefficients; it will be much more efficient to update the subset rather than reconstruct it from scratch at each stage (in fact, before this was introduced, closure extraction was the dominant function for mu-tables.) The following functions are defined : - constructors and destructors : - ClosureIterator(n) : initializes a ClosureIterator of size n; - ~ClosureIterator() : calls standard destructors on components; - iterator operators : - operator bool() : validity check (inlined); - operator()() : returns the current closure (inlined); - operator++() : increments the structure; ****************************************************************************/ namespace schubert { ClosureIterator::ClosureIterator(const SchubertContext& p) :d_schubert(p),d_subSet(p.size()),d_g(p.maxlength()),d_subSize(1), d_visited(p.size()),d_current(0),d_valid(true) { d_visited.reset(); d_visited.setBit(0); d_g.reset(); resetOne(d_subSet); d_subSize.append(1); } void ClosureIterator::operator++() /* This function increments the iterator. In this case, this means updating the subset to hold the closure of the next element. The important thing here is to choose carefully the order of traversal of p. We wish to do this in such a way that the subset can be managed as a stack. What we do is traverse in the lexicographical order of normal forms (so it will be Lex rather than ShortLex). The control structure that manages the traversal is a CoxWord, representing the normal form of the current element. The current element is initially zero. On update, the next element is the first extension of the current element within the context if there is such; otherwise the next extension of the parent of the current element, and so on. In order to facilitate things, we keep track of the number of elements visited. */ { const SchubertContext& p = d_schubert; /* look at extensions of the current word */ LFlags f = p.S() & ~p.rdescent(d_current); for (; f; f &= f-1) { Generator s = firstBit(f); CoxNbr x = p.shift(d_current,s); if (x == undef_coxnbr) continue; if (d_visited.getBit(x)) continue; /* if we get here, x is the next element */ update(x,s); return; } /* if we get here, there are no extensions of the current word */ while (p.length(d_current)) { Length r = p.length(d_current); Generator s = d_g[r-1]-1; d_current = p.shift(d_current,s); for (Generator t = s+1; t < p.rank(); ++t) { if (p.isDescent(d_current,t)) continue; CoxNbr x = p.shift(d_current,t); if (x == undef_coxnbr) continue; if (d_visited.getBit(x)) continue; /* if we get here, x is the next element */ update(x,t); return; } } /* if we get here, we are done */ d_valid = false; return; } /******** private functions *************************************************/ void ClosureIterator::update(const CoxNbr& x, const Generator& s) /* Updates the structure, where the new current element is x, gotten through generator s. The previous length is stored in d_subSet.size(); the update for the subset is to clear all elements of length <= length(x), then extend the resulting subset through s. */ { const SchubertContext& p = d_schubert; d_current = x; d_visited.setBit(x); Length r = p.length(x); d_g.setLength(r); d_g[r-1] = s+1; Length prev_r = d_subSize.size(); /* erase top of subset */ for (Ulong j = d_subSize[r-1]; j < d_subSize[prev_r-1]; ++j) { CoxNbr z = d_subSet[j]; d_subSet.bitMap().clearBit(z); } d_subSet.setListSize(d_subSize[r-1]); p.extendSubSet(d_subSet,s); d_subSize.setSize(r+1); d_subSize[r] = d_subSet.size(); return; } }; /**************************************************************************** Chapter III -- Bruhat order and descent This section contains the definitions for the functions defined in schubert.c, dealing with the Bruhat order and descent sets : - extractClosure(p,q,x) : puts [e,x] in q; - extractInvolutions(p,b) : extracts involutions; - maximize(p,map,f) : extracts maximal elements w.r.t. f; - minimize(p,map,f) : extracts minimal elements w.r.t. f; - shortLexOrder(p,x,y) : checks if x <= y in ShortLex order; ****************************************************************************/ namespace schubert { void extractInvolutions(const SchubertContext& p, BitMap& b) /* This function extracts from b the involutions contained in it. First we check if L(x) = R(x); if yes, we check if x.x = e. */ { BitMap::Iterator last = b.end(); for (BitMap::Iterator i = b.begin(); i != last; ++i) { CoxNbr x = *i; if (p.rdescent(x) != p.ldescent(x)) goto not_involution; /* check if x.x = e */ { CoxNbr xl = x; CoxNbr xr = x; while (xl) { Generator s = p.firstRDescent(xl); xl = p.rshift(xl,s); xr = p.lshift(xr,s); if (p.rdescent(xl) != p.ldescent(xr)) goto not_involution; } } /* if we get here, we have an involution */ continue; not_involution: b.clearBit(x); continue; } } void maximize(const SchubertContext& p, BitMap& b, const LFlags& f) /* This function extracts from b the maximal elements w.r.t. f, by intersecting with the appropriate downsets. */ { LFlags f1 = f; while(f1) { Generator s = firstBit(f1); b &= p.downset(s); f1 &= f1-1; } return; } void minimize(const SchubertContext& p, BitMap& b, const LFlags& f) /* This function extracts from b the minimal elements w.r.t. f, by intersecting with the appropriate upsets. */ { LFlags f1 = f; while(f1) { Generator s = firstBit(f1); b.andnot(p.downset(s)); f1 &= f1-1; } return; } bool shortLexOrder(const SchubertContext& p, const CoxNbr& d_x, const CoxNbr& d_y, const Permutation& order) /* This function checks if x <= y in the ShortLex order of the normal forms w.r.t. the given order (as usual, this means that we compare order[] to compare generators.) In other words, the result is true iff either length(x) < length(y), or lengths are equal and firstterm(x) < firstterm(y), or firstterms are equal (to s), and sx <= sy in ShortLex order. */ { if (d_x == d_y) return true; if (p.length(d_x) < p.length(d_y)) return true; if (p.length(d_x) > p.length(d_y)) return false; CoxNbr x = d_x; CoxNbr y = d_y; Generator s_x = p.firstLDescent(x,order); Generator s_y = p.firstLDescent(y,order); while (s_x == s_y) { x = p.lshift(x,s_x); y = p.lshift(y,s_y); s_x = p.firstLDescent(x,order); s_y = p.firstLDescent(y,order); } if (order[s_x] < order[s_y]) return true; if (order[s_x] > order[s_y]) return false; return false; // unreachable } }; /**************************************************************************** Chapter IV -- Input/output This section defines the input/output functions declared in schubert.h : - print(file,p) : prints the context on a file; - printBitMap(file,b,p,I) : prints a BitMap; - printPartition(file,pi,p,I) : prints a partition; - printPartition(file,pi,b,p,I) : prints a partition restricted to a BitMap; ****************************************************************************/ namespace schubert { void print(FILE* file, const SchubertContext& p) /* This function prints out the contents of the Schubert context. */ { fprintf(file,"size : %lu maxlength : %lu",static_cast(p.size()), static_cast(p.maxlength())); fprintf(file,"\n\n"); for (CoxNbr x = 0; x < p.size(); ++x) { fprintf(file,"%4lu : ",static_cast(x)); for (Generator s = 0; s < p.rank(); ++s) { if (p.rshift(x,s) == undef_coxnbr) fprintf(file,"%4s","*"); else fprintf(file,"%4lu",static_cast(p.rshift(x,s))); } fprintf(file,";"); for (Generator s = 0; s < p.rank(); ++s) { if (p.lshift(x,s) == undef_coxnbr) fprintf(file,"%4s","*"); else fprintf(file,"%4lu",static_cast(p.lshift(x,s))); } fprintf(file,";"); fprintf(file," {"); const CoatomList& c = p.hasse(x); for (Ulong j = 0; j < c.size(); ++j) { fprintf(file,"%lu",static_cast(c[j])); if (j+1 < c.size()) /* there is more to come */ fprintf(file,","); } fprintf(file,"}"); fprintf(file," R:("); for (LFlags f = p.rdescent(x); f;) { fprintf(file,"%lu",static_cast(firstBit(f)+1)); f &= f-1; if (f) /* there is more to come */ fprintf(file,","); } fprintf(file,")"); fprintf(file," L:("); for (LFlags f = p.ldescent(x); f;) { fprintf(file,"%lu",static_cast(firstBit(f)+1)); f &= f-1; if (f) /* there is more to come */ fprintf(file,","); } fprintf(file,")"); fprintf(file,"\n"); } fprintf(file,"\nStar operations :\n\n"); for (CoxNbr x = 0; x < p.size(); ++x) { fprintf(file,"%4lu : ",static_cast(x)); for (Ulong r = 0; r < 2*p.nStarOps(); ++r) { if (p.star(x,r) == undef_coxnbr) fprintf(file,"%5s","*"); else fprintf(file,"%5lu",static_cast(p.star(x,r))); } fprintf(file,"\n"); } fprintf(file,"\n"); return; } void printBitMap(FILE* file, const BitMap& b, const SchubertContext& p, const Interface& I) /* This function prints the elements of the bitmap (assumed to hold a subset of the context) on the file. */ { bool first = true; fprintf(file,"{"); for (BitMap::Iterator i = b.begin(); i != b.end(); ++i) { if (first) first = false; else fprintf(file,","); CoxWord g(0); p.append(g,*i); I.print(file,g); } fprintf(file,"}"); } void printPartition(FILE* file, const Partition& pi, const SchubertContext& p, const Interface& I) /* This function prints the partition pi, assumed to hold a partition of the context p. */ { Ulong count = 0; for (PartitionIterator i(pi); i; ++i) { const Set& c = i(); fprintf(file,"%lu(%lu):{",count,c.size()); for (Ulong j = 0; j < c.size(); ++j) { CoxWord g(0); p.append(g,c[j]); I.print(file,g); if (j+1 < c.size()) /* there is more to come */ fprintf(file,","); } fprintf(file,"}\n"); ++count; } return; } void printPartition(FILE* file, const Partition& pi, const BitMap& b, const SchubertContext& p, const Interface& I) /* Prints the partition pi restricted to the subset flagged by b. */ { List q(b.begin(),b.end()); // replaces readBitMap Partition pi_b(b.begin(),b.end(),pi); Ulong count = 0; for (PartitionIterator i(pi_b); i; ++i) { const Set& c = i(); fprintf(file,"%lu(%lu):{",count,c.size()); for (Ulong j = 0; j < c.size(); ++j) { CoxWord g(0); p.append(g,q[c[j]]); I.print(file,g); if (j+1 < c.size()) /* there is more to come */ fprintf(file,","); } fprintf(file,"}\n"); ++count; } return; } }; /**************************************************************************** Chapter V -- Utilities This section defines some utility functions : - betti(h,y,p) : puts in h the betti numbers of [e,y]; - min(c,nfc) : extracts the minimal element from c; - extractMaximals(p,c) : extracts from c the list of its maximal elements; - minDescent(f,order) : finds the smallest element in f w.r.t. order; - readBitMap(c,b) : reads b into c; - resetOne(SubSet& q) : resets q to hold the one-elements subset {0}; - setBitMap(b,c) : reads c into b; - sum(h) : returns the sum of the terms in h; ****************************************************************************/ namespace schubert { void betti(Homology& h, const CoxNbr& y, const SchubertContext& p) /* This function puts the ordinary betti numbers of the row in h, in a simple-minded approach. No overflow is possible here. It is assumed that row is a row in kllist. */ { BitMap b(0); p.extractClosure(b,y); h.setSize(p.length(y)+1); h.setZero(); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator x = b.begin(); x != b_end; ++x) { h[p.length(*x)]++; } return; } Ulong min(const Set& c, NFCompare& nfc) /* This function extracts the minimal element form c. It is defined for Set instead of List so as to be able to apply it directly to partition classes. */ { if (c.size() == 0) return undef_coxnbr; Ulong m = c[0]; for (Ulong j = 1; j < c.size(); ++j) { if (!nfc(m,c[j])) m = c[j]; } return m; } void extractMaximals(const SchubertContext& p, List& c) /* This function erases from c all elements that are not maximal elements for the Bruhat order among the entries in c. It is assumed that c is sorted in an ordering compatible with the Bruhat order; so if we start from the top, we will always encounter a maximal element before any lower one. */ { Ulong extr_count = 0; for (Ulong j = c.size(); j;) { --j; for (Ulong i = c.size()-extr_count; i < c.size(); ++i) { if (p.inOrder(c[j],c[i])) /* forget j */ goto nextj; } extr_count++; c[c.size()-extr_count] = c[j]; nextj: continue; } c.setData(c.ptr()+c.size()-extr_count,0,extr_count); c.setSize(extr_count); return; } void extractMaximals(const SchubertContext& p, List& c, List& a) /* Like the previous one, but puts the indices in c of the maximal elements in the list a. */ { List e(0); a.setSize(0); for (Ulong j = c.size(); j;) { --j; for (Ulong i = 0; i < e.size(); ++i) { if (p.inOrder(c[j],e[i])) /* forget j */ goto nextj; } a.append(j); e.append(c[j]); nextj: continue; } a.reverse(); return; } Ulong minDescent(const LFlags& d_f, const Permutation& order) /* Returns the set bit position in f for which order is smallest. In practice, order is the external numbering of the generators; so this gives the internal number of the descent generator with smallest external number. NOTE : the return value is BITS(LFlags) if f is empty. */ { LFlags f = d_f; Ulong m = firstBit(f); f &= f-1; for (; f; f &= f-1) { Ulong m1 = firstBit(f); if (order[m1] < order[m]) m = m1; } return m; } void readBitMap(List& c, const BitMap& b) /* This function reads in c from b (analogous to readBitMap in bits::SubSet). */ { c.setSize(b.bitCount()); BitMap::Iterator i = b.begin(); for (Ulong j = 0; j < c.size(); ++j) { c[j] = *i; ++i; } } }; namespace { void resetOne(SubSet& q) /* Resets q to hold the one-element subset {0}. Forwards the error MEMORY_WARNING if CATCH_MEMORY_ERROR is set. */ { q.reset(); q.add(0); /* an error may have been set here */ return; } }; namespace schubert { void setBitMap(BitMap& b, const List& c) /* Reads c into b. It is assumed that b has already been set to the current context size. */ { b.reset(); for (Ulong j = 0; j < c.size(); j++) b.setBit(c[j]); } Ulong sum(const Homology& h) { Ulong a = 0; for (Ulong j = 0; j < h.size(); ++j) { a += h[j]; } return a; } }; positivity_final/schubert.h0000600000175000017500000003472510011171251017622 0ustar duclouxducloux00000000000000/* This is schubert.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef SCHUBERT_H /* guard against multiple inclusions */ #define SCHUBERT_H #include "globals.h" #include "coxtypes.h" namespace schubert { using namespace globals; using namespace coxtypes; }; /******** type declarations *************************************************/ namespace schubert { class ClosureIterator; class SchubertContext; class StandardSchubertContext; struct NFCompare; typedef List CoatomList; typedef List Homology; }; /******** function declarations *********************************************/ #include "bits.h" #include "interface.h" namespace schubert { using namespace bits; using namespace interface; }; namespace schubert { void betti(Homology& h, const CoxNbr& y, const SchubertContext& p); void extractInvolutions(const SchubertContext& p, BitMap& b); void extractMaximals(const SchubertContext& p, List& c); void extractMaximals(const SchubertContext& p, List& c, List& a); void maximize(const SchubertContext& p, BitMap& b, const LFlags& f); Ulong min(const Set& c, NFCompare& nfc); Ulong minDescent(const LFlags& f, const Permutation& order); void minimize(const SchubertContext& p, BitMap& b, const LFlags& f); void print(FILE* file, const SchubertContext& p); void printBitMap(FILE* file, const BitMap& pi, const SchubertContext& p, const Interface& I); void printList(FILE* file, const List& v, const SchubertContext& p, const Interface& I); void printPartition(FILE* file, const Partition& pi, const SchubertContext& p, const Interface& I); void printPartition(FILE* file, const Partition& pi, const BitMap& b, const SchubertContext& p, const Interface& I); void readBitMap(List& c, const BitMap& b); bool shortLexOrder(const SchubertContext& p, const CoxNbr& x, const CoxNbr& y, const Permutation& order); void setBitMap(BitMap& b, const List& c); Ulong sum(const Homology& h); }; /******** type definitions *************************************************/ #include "graph.h" #include "io.h" #include "list.h" #include "stack.h" namespace schubert { using namespace graph; using namespace io; using namespace list; using namespace stack; }; namespace schubert { struct NFCompare { const SchubertContext& p; const Permutation& order; NFCompare(const SchubertContext& q, const Permutation& generator_ordering) :p(q),order(generator_ordering) {}; ~NFCompare() {}; bool operator()(const CoxNbr& x, const CoxNbr& y) {return shortLexOrder(p,x,y,order);} }; class SchubertContext { friend class ClosureIterator; public: void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(SchubertContext));} virtual ~SchubertContext() {}; /* accessors */ virtual CoxWord& append(CoxWord& g, const CoxNbr& x) const = 0; virtual LFlags ascent(const CoxNbr& x) const = 0; virtual CoxNbr contextNumber(const CoxWord& g) const = 0; virtual LFlags descent(const CoxNbr& x) const = 0; virtual const BitMap& downset(const Generator& s) const = 0; virtual void extendSubSet(SubSet& q, const Generator& s) const = 0; virtual void extractClosure(BitMap& b, const CoxNbr& x) const = 0; virtual Generator firstDescent(const CoxNbr& x) const = 0; virtual Generator firstLDescent(const CoxNbr& x) const = 0; virtual Generator firstRDescent(const CoxNbr& x) const = 0; virtual Generator firstDescent(const CoxNbr& x, const Permutation& order) const = 0; virtual Generator firstLDescent(const CoxNbr& x, const Permutation& order) const = 0; virtual Generator firstRDescent(const CoxNbr& x, const Permutation& order) const = 0; virtual const CoatomList& hasse(const CoxNbr& x) const = 0; virtual bool inOrder(CoxNbr x, CoxNbr y) const = 0; virtual bool isDescent(const CoxNbr& x, const Generator& s) const = 0; virtual LFlags lascent(const CoxNbr& x) const = 0; virtual LFlags ldescent(const CoxNbr& x) const = 0; virtual Length length(const CoxNbr& x) const = 0; virtual CoxNbr lshift(const CoxNbr& x, const Generator& s) const = 0; virtual CoxNbr maximize(const CoxNbr& x, const LFlags& f) const = 0; virtual Length maxlength() const = 0; virtual CoxNbr minimize(const CoxNbr& x, const LFlags& f) const = 0; virtual CoxWord& normalForm(CoxWord& g, const CoxNbr& x, const Permutation& order) const = 0; virtual Ulong nStarOps() const = 0; virtual const BitMap& parity(const CoxNbr& x) const = 0; virtual Rank rank() const = 0; virtual LFlags rascent(const CoxNbr& x) const = 0; virtual LFlags rdescent(const CoxNbr& x) const = 0; virtual CoxNbr rshift(const CoxNbr& x, const Generator& s) const = 0; virtual LFlags S() const = 0; virtual CoxNbr shift(const CoxNbr& x, const Generator& s) const = 0; virtual CoxNbr size() const = 0; virtual CoxNbr star(CoxNbr x, const Ulong& r) const = 0; virtual LFlags twoDescent(const CoxNbr& x) const = 0; virtual const Type& type() const = 0; /* modifiers */ virtual CoxNbr extendContext(const CoxWord& g) = 0; virtual void permute(const Permutation& a) = 0; virtual void revertSize(const Ulong& n) = 0; virtual void setSize(const Ulong& n) = 0; /* input-output */ virtual String& append(String&, const CoxNbr& x) const = 0; virtual String& append(String&, const CoxNbr& x, const Interface& I) const = 0; virtual void print(FILE* file, const CoxNbr& x) const = 0; virtual void print(FILE* file, const CoxNbr& x, const Interface& I) const = 0; }; class StandardSchubertContext:public SchubertContext { private: /* private class declaration */ class ContextExtension { private: StandardSchubertContext& d_schubert; Ulong d_size; CoxNbr* d_shift; CoxNbr* d_star; public: void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(ContextExtension));} ContextExtension(StandardSchubertContext& p, const Ulong& c); ~ContextExtension(); Ulong size() {return d_size;} }; const CoxGraph& d_graph; Rank d_rank; Length d_maxlength; CoxNbr d_size; List d_length; List d_hasse; List d_descent; List d_shift; List d_star; BitMap* d_downset; BitMap* d_parity; SubSet d_subset; Stack d_history; /* private member functions */ void fillCoatoms(const Ulong& first, const Generator& s); void fillDihedralShifts(const CoxNbr& x, const Generator& s); void fillShifts(const CoxNbr& first, const Generator& s); void fillStar(const CoxNbr& first); void fullExtension(SubSet& q, const Generator& s); void subSetExtension(SubSet& q, const Generator& s) const; public: void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(StandardSchubertContext));} /* friend declaration */ friend ContextExtension::ContextExtension(StandardSchubertContext&, const Ulong& c); friend ContextExtension::~ContextExtension(); /* constructors and destructors */ StandardSchubertContext(const CoxGraph& G); ~StandardSchubertContext(); /* accessors */ CoxWord& append(CoxWord& g, const CoxNbr& x) const; LFlags ascent(const CoxNbr& x) const; /* inlined */ CoxNbr contextNumber(const CoxWord& g) const; LFlags descent(const CoxNbr& x) const; /* inlined */ const BitMap& downset(const Generator& s) const; /* inlined */ void extendSubSet(SubSet& q, const Generator& s) const; void extractClosure(BitMap& b, const CoxNbr& x) const; Generator firstDescent(const CoxNbr& x) const; /* inlined */ Generator firstLDescent(const CoxNbr& x) const; /* inlined */ Generator firstRDescent(const CoxNbr& x) const; /* inlined */ Generator firstDescent(const CoxNbr& x, const Permutation& order) const; /* inlined */ Generator firstLDescent(const CoxNbr& x, const Permutation& order) const; /* inlined */ Generator firstRDescent(const CoxNbr& x, const Permutation& order) const; /* inlined */ const CoatomList& hasse(const CoxNbr& x) const; /* inlined */ bool inOrder(CoxNbr x, CoxNbr y) const; bool isDescent(const CoxNbr& x, const Generator& s) const; /* inlined */ bool isSuperExtremal(const CoxNbr& x, const CoxNbr& y) const; LFlags lascent(const CoxNbr& x) const; /* inlined */ LFlags ldescent(const CoxNbr& x) const; /* inlined */ Length length(const CoxNbr& x) const; /* inlined */ CoxNbr lshift(const CoxNbr& x, const Generator& s) const; /* inlined */ CoxNbr maximize(const CoxNbr& x, const LFlags& f) const; Length maxlength() const; /* inlined */ CoxNbr minimize(const CoxNbr& x, const LFlags& f) const; CoxWord& normalForm(CoxWord& g, const CoxNbr& x, const Permutation& order) const; Ulong nStarOps() const; /* inlined */ const BitMap& parity(const CoxNbr& x) const; /* inlined */ Rank rank() const; /* inlined */ LFlags rascent(const CoxNbr& x) const; /* inlined */ LFlags rdescent(const CoxNbr& x) const; /* inlined */ CoxNbr rshift(const CoxNbr& x, const Generator& s) const; /* inlined */ LFlags S() const; /* inlined */ CoxNbr shift(const CoxNbr& x, const Generator& s) const; /* inlined */ CoxNbr size() const; /* inlined */ CoxNbr star(CoxNbr x, const Ulong& r) const; /* inlined */ LFlags twoDescent(const CoxNbr& x) const; const Type& type() const; /* inlined */ /* manipulators */ CoxNbr extendContext(const CoxWord& g); void permute(const Permutation& a); void revertSize(const Ulong& n); void setSize(const Ulong& n); /* i/o */ String& append(String&, const CoxNbr& x) const; String& append(String&, const CoxNbr& x, const Interface& I) const; void print(FILE* file, const CoxNbr& x) const; void print(FILE* file, const CoxNbr& x, const Interface& I) const; }; class ClosureIterator { private: const SchubertContext& d_schubert; SubSet d_subSet; CoxWord d_g; List d_subSize; BitMap d_visited; CoxNbr d_current; bool d_valid; /* private functions */ void update(const CoxNbr& x, const Generator& s); public: /* constructors and destructors */ ClosureIterator(const SchubertContext& p); ~ClosureIterator() {}; /* iterator operators */ operator bool() const; /* inlined */ void operator++(); const SubSet& operator()() const; /* inlined */ /* accessors */ const CoxNbr& current() const; /* inlined */ }; }; /******** inline definitions **********************************************/ namespace schubert { inline LFlags StandardSchubertContext::ascent(const CoxNbr& x) const {return ~d_descent[x]&leqmask[2*d_rank-1];} inline LFlags StandardSchubertContext::descent(const CoxNbr& x) const {return d_descent[x];} inline const BitMap& StandardSchubertContext::downset(const Generator& s) const {return d_downset[s];} inline Generator StandardSchubertContext::firstDescent(const CoxNbr& x) const {return firstBit(descent(x));} inline Generator StandardSchubertContext::firstLDescent(const CoxNbr& x) const {return firstBit(ldescent(x));} inline Generator StandardSchubertContext::firstRDescent(const CoxNbr& x) const {return firstBit(rdescent(x));} inline Generator StandardSchubertContext::firstDescent(const CoxNbr& x, const Permutation& order) const {return firstRDescent(x,order);} inline Generator StandardSchubertContext::firstLDescent(const CoxNbr& x, const Permutation& order) const {return minDescent(ldescent(x),order);} inline Generator StandardSchubertContext::firstRDescent(const CoxNbr& x, const Permutation& order) const {return minDescent(rdescent(x),order);} inline const CoatomList& StandardSchubertContext::hasse(const CoxNbr& x) const {return d_hasse[x];} inline bool StandardSchubertContext::isDescent(const CoxNbr& x, const Generator& s) const {return d_descent[x]&lmask[s];} inline LFlags StandardSchubertContext::lascent(const CoxNbr& x) const {return ~ldescent(x)&leqmask[d_rank-1];} inline LFlags StandardSchubertContext::ldescent(const CoxNbr& x) const {return d_descent[x] >> d_rank;} inline Length StandardSchubertContext::length(const CoxNbr& x) const {return d_length[x];} inline CoxNbr StandardSchubertContext::lshift(const CoxNbr& x, const Generator& s) const {return d_shift[x][d_rank+s];} inline Length StandardSchubertContext::maxlength() const {return d_maxlength;} inline Ulong StandardSchubertContext::nStarOps() const {return d_graph.starOps().size();} inline const BitMap& StandardSchubertContext::parity(const CoxNbr& x) const {return d_parity[d_length[x]%2];} inline Rank StandardSchubertContext::rank() const {return d_rank;} inline LFlags StandardSchubertContext::rascent(const CoxNbr& x) const {return ~rdescent(x)&leqmask[d_rank-1];} inline LFlags StandardSchubertContext::rdescent(const CoxNbr& x) const {return d_descent[x] & leqmask[d_rank-1];} inline CoxNbr StandardSchubertContext::rshift(const CoxNbr& x, const Generator& s) const {return d_shift[x][s];} inline LFlags StandardSchubertContext::S() const {return leqmask[d_rank-1];} inline CoxNbr StandardSchubertContext::shift(const CoxNbr& x, const Generator& s) const {return d_shift[x][s];} inline CoxNbr StandardSchubertContext::size() const {return d_size;} inline CoxNbr StandardSchubertContext::star(CoxNbr x, const Ulong& r) const {return d_star[x][r];} inline const Type& StandardSchubertContext::type() const {return d_graph.type();} inline const SubSet& ClosureIterator::operator()() const {return d_subSet;} inline ClosureIterator::operator bool() const {return d_valid;} inline const CoxNbr& ClosureIterator::current() const {return d_current;} }; #endif positivity_final/search.cpp0000600000175000017500000000000010011171251017556 0ustar duclouxducloux00000000000000positivity_final/search.h0000600000175000017500000000356110034772412017255 0ustar duclouxducloux00000000000000/* This is search.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef SEARCH_H /* guard against multiple inclusions */ #define SEARCH_H #include "globals.h" namespace search { using namespace globals; }; /******** type declarations *************************************************/ namespace search { template class BinaryTree; template struct TreeNode; }; /******** function declarations *********************************************/ namespace search { template void print(FILE*, const BinaryTree&); template void print(FILE*, TreeNode*, const char*); }; /******** type definitions **************************************************/ #include "list.h" namespace search { using namespace list; }; namespace search { template struct TreeNode { TreeNode* left; TreeNode* right; T data; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TreeNode));} TreeNode(const T& a); virtual ~TreeNode(); }; template class BinaryTree { protected: Ulong d_size; TreeNode* d_root; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(BinaryTree));} BinaryTree(); ~BinaryTree(); /* accessors */ Ulong size() const; TreeNode* root() const; /* modifiers */ T* find(const T& a); }; }; /******** inline definitions ************************************************/ namespace search { template inline Ulong BinaryTree::size() const {return d_size;} template inline TreeNode* BinaryTree::root() const {return d_root;} }; #include "search.hpp" #endif positivity_final/search.hpp0000600000175000017500000000704210034256540017612 0ustar duclouxducloux00000000000000/* This is search.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "memory.h" namespace search { using namespace memory; }; /**************************************************************************** This file contains code to implement binary search trees. First we implement an elementary binary tree search. This will allow us to study its behaviour and choose the best way to improve. ****************************************************************************/ /**************************************************************************** Chapter I -- The BinaryTree class. This section provides the definition of the functions in the BinaryTree class. The functions are the following : constructors and destructors : - BinaryTree(); - ~BinaryTree(); accessors : - size() : returns the number of nodes in the tree; (inlined) - root() : returns the root of the tree; (inlined) modifiers : - find(a) : finds the element a in the tree; ****************************************************************************/ namespace search { template BinaryTree::BinaryTree() :d_size(0), d_root(0) {} template BinaryTree::~BinaryTree() /* The tree is destructed recursively by ~TreeNode(). */ { delete d_root; } template T* BinaryTree::find(const T& a) /* Finds the element a in the tree; creates a new node if a is not found. It is assumed that operator< is defined for polynomials. NOTE : if CATCH_MEMORY_OVERFLOW is set, the function returns 0 on error. */ { TreeNode** c = &d_root; while (*c) { if (a == (*c)->data) /* a was found */ return &((*c)->data); if (a < (*c)->data) /* go to left tree */ c = &((*c)->left); else /* go to right tree */ c = &((*c)->right); } /* at this point c points to the insertion point */ *c = new TreeNode(a); if (ERRNO) /* memory overflow */ return 0; d_size++; return &((*c)->data); } }; /***************************************************************************** Chapter II -- The TreeNode class This section defines functions for manipulating TreeNodes : - TreeNode(a) : constructor with value; *****************************************************************************/ namespace search { template TreeNode::TreeNode(const T& a):data(a) {} template TreeNode::~TreeNode() { delete left; delete right; } }; /***************************************************************************** Chapter III -- Utilities. This section defines some utility functions associated with binary trees : - print(file,t) : prints the tree on the file; *****************************************************************************/ namespace search { template void print(FILE* file, const BinaryTree& t) /* Prints out the tree on the output file. */ { fprintf(file,"size : %lu\n\n",t.size()); print(file,t.root()); return; } template void print(FILE* file, TreeNode* c, const char* varname) /* Recursively prints out the nodes, indenting to express the tree structure. */ { static int indentation = 0; if (c == 0) return; // indentation += 2; print(file,c->left,varname); // indentation -= 2; fprintf(file,"%*s",indentation,""); print(file,c->data,varname); fprintf(file,"\n"); // indentation += 2; print(file,c->right,varname); // indentation -= 2; return; } }; positivity_final/special.cpp0000600000175000017500000007104110256222016017755 0ustar duclouxducloux00000000000000/* This is special.cpp Coxeter version 3.0_demo Copyright (C) 2001 Fokko du Cloux See file main.cpp for full copyright notice */ #include "special.h" #include "directories.h" #include "interactive.h" #include "commands.h" #include "fcoxgroup.h" #include "cells.h" #include "interactive.h" #include "search.h" #include /***************************************************************************** This module contains code to study the positivity of the structure constants in the Hecke algebra, in the k-l c-basis. This asserts that if we write : c_x.c_y = sum_{z}b_{x,y,z}c_z then the coefficients b_{x,y,z} are (Laurent) polynomials with non-negative coefficients. It is known through deep geometrical arguments to hold when W is crystallographic. Our approach consists in computing c_x.c_y inductively, for fixed y, through the formula c_x = c_s.c_{sx} - \sum_{z v, and if s.v < v, is given by c_s.c_v = (q^{1/2}+q^{-1/2}) c_v. So the basic input for this computation are the mu-coefficients for the group, which are readily accessible from the program. NOTE : the printouts always outputs only the nonnegative-degree part of the Laurent polynomials, as they are symmetric w.r.t. v -> v^{-1}. ******************************************************************************/ /******** local definitions **************************************************/ namespace { using namespace special; using namespace fcoxgroup; using namespace interactive; void special_f(); void special_h(); void cprod_f(); void cycltable_f(); void decrklpol_f(); void klplist_f(); void positivity_f(); void cprod_h(); void cycltable_h(); void decrklpol_h(); void klplist_h(); void positivity_h(); const char* special_tag = "user-defined command"; const char* cprod_tag = "multiplies two elements in the k-l basis"; const char* cycltable_tag = "prints out the table of all c_x.c_y for a given y"; const char* decrklpol_tag = "checks if k-l polynomials are decreasing"; const char* klplist_tag = "prints the list of all polynomials occurring as k-l polynomials"; const char* positivity_tag = "checks non-negativity of structure coefficients and writes them down"; typedef unsigned Coeff; const Coeff COEFF_MAX = UINT_MAX; typedef Polynomial Pol; const Pol& one(); // convenience classes class GraphData { private: List > > d_edge; List > > d_coeff; Ulong d_size; public: // constructors and destructors GraphData():d_edge(0),d_coeff(0),d_size(0) {}; GraphData(const WGraph&, const Rank&); ~GraphData() {}; // accessors const List& coeff(const Generator& s, const CoxNbr& x) const {return d_coeff[s][x];} const List& edge(const Generator& s, const CoxNbr& x) const {return d_edge[s][x];} const Ulong size() const {return d_size;} }; // PolTree is a binary tree with additional data class PolTree:public search::BinaryTree { private: Ulong d_maxCoeff; public: // constructors and destructors PolTree():d_maxCoeff(0) {} ~PolTree() {} // acessors Ulong maxCoeff() const {return d_maxCoeff;} // manipulators void reset(); Pol* find(const Pol& p); }; class PolTable { private: List d_data; List d_row; PolTree d_tree; public: // constructors and destructors PolTable() {}; PolTable(const BitMap&); PolTable(const Ulong&, const Ulong&); ~PolTable() {}; // accessors Ulong maxCoeff() const {return d_tree.maxCoeff();} const Pol** row(const Ulong& i) const {return d_row[i];} Ulong size() const {return d_row.size();} // manipulators const Pol*& operator()(const Ulong& i, const Ulong& j) {return d_row[i][j];} void setZero() {d_data.setZero();} void setZero(const Ulong& i, const Ulong& j) {d_row[i][j] = 0;} void write(const Pol& p, const Ulong& i, const Ulong& j) {d_row[i][j] = d_tree.find(p);} // temporary stuff PolTree& tree() {return d_tree;} }; // functions for the positivity check void addSimpleTerm(List&, const CoxNbr&, const Pol&); void addTerm(List&, const List&, const List&, const Pol&); void extendTable(PolTable&, const WGraph&, const SchubertContext&, const CoxNbr&, const GraphData&); bool fillTable(PolTable&, const WGraph&, const SchubertContext&, const CoxNbr&, const GraphData&); bool isSmaller(const kl::KLPol&, const kl::KLPol&); bool isUnimodal(const Pol& pol); void prettyPrint(FILE*, const Pol& pol, const Degree&); void printRow(FILE*, const Pol**, FiniteCoxGroup*); void printTable(FILE*, const PolTable&, FiniteCoxGroup*); void safeAdd(Pol&, const Pol&); void safeAdd(Pol&, const Pol&, const KLCoeff&); void safeSubtract(Pol&, const Pol&); void safeSubtract(Pol&, const Pol&, const KLCoeff&); void subtract(List&, const Pol**, const KLCoeff&); void writeRow(List&, PolTable&, const Ulong& i); }; /************************************************************************ Chapter I -- Functions for the special commands. This section defines the functions provided by special.c ************************************************************************/ void special::addSpecialCommands(commands::CommandTree* tree) /* This function should be edited if you want to add new commands to the system, instead of just editing the "special" command. Adding a command is easy : you should choose a name for it (an arbitrary string; if it already exists it will replace the existing command), a "tag" (used for help purposes; special_tag will do), a function which should take no arguments and return void, which will be executed by the command, and a help function (the empty function will do; this is already provided as relax_f, provided by commands.h). The commands are added to the main command tree of the program (the tree argument is used for convienience, since this function is called when mainCommandTree() is not yet functional); it would also be possible to add special command trees, but we have decided to leave this to users willing to delve into commands.c. */ { using namespace commands; /* prototype line for adding a special command */ tree->add("special",special_tag,&special_f,&special_h); /* add user-defined commands here ... */ tree->add("cprod",cprod_tag,&cprod_f,&cprod_h); tree->add("cycltable",cycltable_tag,&cycltable_f,&cycltable_h); tree->add("decrklpol",decrklpol_tag,&decrklpol_f,&decrklpol_h); tree->add("klplist",klplist_tag,&klplist_f,&klplist_h); tree->add("positivity",positivity_tag,&positivity_f,&positivity_h); return; } namespace { void cprod_f() /* Prints the product of two elements in the k-l basis. Tries to avoid unnecessary memory allocations, by allocating only rows in the table for elements <= x. */ { using namespace commands; // check if the current group is finite; exit otherwise FiniteCoxGroup* W = dynamic_cast(currentGroup()); if (W == 0) { fprintf(stderr,"sorry, group must be finite\n"); return; } W->fullContext(); // make schubert context available for the full group // (this does not yet compute mu-coefficients) // get the two elements CoxWord g(0); printf("first : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr x = W->contextNumber(g); fprintf(stdout,"second : "); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } CoxNbr y = W->contextNumber(g); // fill the mu-table; make the W-graph W->fillMu(); WGraph X(0); cells::lWGraph(X,W->kl()); // initialize the computation GraphData gd(X,W->rank()); BitMap bm(W->order()); W->extractClosure(bm,x); // put in bm a bitmap representing [e,x] PolTable pt(bm); // initialize table for z = e pt.write(one(),0,y); // the others are initialized to 0 already // fill table BitMap::Iterator bm_end = bm.end(); for (BitMap::Iterator i = ++bm.begin(); i != bm_end; ++i) { CoxNbr z = *i; extendTable(pt,X,W->schubert(),z,gd); } // print line printRow(stdout,pt.row(x),W); printf("\n"); return; } void cycltable_f() /* This command prompts the user for an element y in the group, then prints out the various c_x.c_y, for x in the group. */ { // check if the current group is finite; exit otherwise FiniteCoxGroup* W = dynamic_cast(commands::currentGroup()); if (W == 0) { fprintf(stderr,"sorry, group must be finite\n"); return; } W->fullContext(); // make schubert context available for the full group // (this does not yet compute mu-coefficients) // get the element CoxWord g(0); printf("enter your element (finish with a carriage return) :\n"); g = interactive::getCoxWord(W); if (ERRNO) { Error(ERRNO); return; } // fill the mu-table; make the W-graph CoxNbr y = W->contextNumber(g); W->fillMu(); WGraph X(0); cells::lWGraph(X,W->kl()); // initialize the computation GraphData gd(X,W->rank()); PolTable pt(W->order(),W->order()); // fill table fillTable(pt,X,W->schubert(),y,gd); // output the result to a user-provided file OutputFile file; // the constructor lets the user specify a file printTable(file.f(),pt,W); return; } void decrklpol_f() /* Checks whether for each x <= z <= y the polynomial P_{x,y}-P_{z,y} has non-negative coefficients. Here we may replace z by its extremalization, and then the same for x, so that it suffices to check this for x and z extremal. It is enough to do the check when y_inverse >= y. We proceed as follows : for each such y, we run through [e,y], and check that for all z in [e,y], and each coatom x of z, we have P_{z,y} <= P_{x,y}. */ { // check if the current group is finite; exit otherwise FiniteCoxGroup* W = dynamic_cast(commands::currentGroup()); if (W == 0) { fprintf(stderr,"sorry, group must be finite\n"); return; } // set the context to the full group, and compute the k-l polynomials W->fullContext(); W->fillKL(); // main loop for (CoxNbr y = 0; y < W->order(); ++y) { if (W->inverse(y) < y) continue; // traverse the interval [e,y] BitMap b(0); W->extractClosure(b,y); // put in b a bitmap representing [e,y] BitMap::Iterator b_end = b.end(); for (BitMap::Iterator i = b.begin(); i != b_end; ++i) { CoxNbr z = *i; // current element of [e,y] const kl::KLPol& p_zy = W->klPol(z,y); // traverse the coatom set of z const CoatomList& c = W->coatoms(z); for (Ulong j = 0; j < c.size(); ++j) { CoxNbr x = c[j]; const kl::KLPol& p_xy = W->klPol(x,y); if (!isSmaller(p_zy,p_xy)) { // found a counterexample // this is not expected to ever happen fprintf(stderr,"error! x = %lu, z = %lu, y = %lu\n",x,y,z); fprintf(stderr,"P_{x,y} = "); print(stderr,p_xy,"q"); fprintf(stderr,"\n"); fprintf(stderr,"P_{z,y} = "); print(stderr,p_zy,"q"); fprintf(stderr,"\n"); return; } } } printf("%lu\r",y); // print a counter to show progress } printf("check was successful\n"); return; } void klplist_f() /* Prints the full list of all distinct k-l polynomials. */ { // check if the current group is finite; exit otherwise FiniteCoxGroup* W = dynamic_cast(commands::currentGroup()); if (W == 0) { fprintf(stderr,"sorry, group must be finite\n"); return; } // set the context to the full group, and compute the k-l polynomials W->fullContext(); W->fillKL(); // output the list of polynomials to a user-defined file OutputFile file; // the constructor lets the user specify a file print(file.f(),W->kl().tree().root(),"q"); return; } void positivity_f() /* Checks out the non-negativity of the structure constants of the Hecke algebra in the k-l basis. The function starts out by checking that the group is finite. Then it makes sure that all the mu-coefficients for W are available, and initializes the tables that are used in the computation : gd holds the data from the W-graph in the precise form in which it shall be needed, and pt is the main table for the computation, consisting of a matrix of |W|^2 polynomial pointers, and a tree to hold the actual polynomials. For H4, the table of polynomial pointers is the biggest memory requirement, and takes up about 800 MB for a 32-bit system (and twice that amount on a 64-bit system!) The computation then proceeds as explained in the article, filling the table for fixed y. The only material memory-requirement from now on comes from the growth of pt.d_tree. Here we do not try to keep the polynomials so we simply flush the tree at each pass. */ { // check if the current group is finite; exit otherwise FiniteCoxGroup* W = dynamic_cast(commands::currentGroup()); if (W == 0) { fprintf(stderr,"sorry, group must be finite\n"); return; } // set the context to the full group, and compute the mu coefficients W->fullContext(); W->fillMu(); // construct the (left) W-graph of the full group WGraph X(0); cells::lWGraph(X,W->kl()); // initialize the computation GraphData gd(X,W->rank()); PolTable pt(W->order(),W->order()); // reset positivity_log and error_log fclose(fopen("positivity_log","w")); fclose(fopen("error_log","w")); // run through computation for (Ulong y = 0; y < W->order(); ++y) { pt.setZero(); fillTable(pt,X,W->schubert(),y,gd); pt.tree().reset(); FILE* log = fopen("positivity_log","a"); fprintf(log,"%lu: maxcoeff = %lu\n",y,pt.maxCoeff()); fclose(log); } return; } void special_f() { fprintf(stderr,"not implemented\n"); return; } void cprod_h() { printFile(stderr,"cprod.help",directories::MESSAGE_DIR); return; } void cycltable_h() { printFile(stderr,"cycltable.help",directories::MESSAGE_DIR); return; } void decrklpol_h() { printFile(stderr,"decrklpol.help",directories::MESSAGE_DIR); return; } void klplist_h() { printFile(stderr,"klplist.help",directories::MESSAGE_DIR); return; } void positivity_h() { printFile(stderr,"positivity.help",directories::MESSAGE_DIR); return; } void special_h() {} }; /***************************************************************************** Chapter II -- The GraphData class. This class makes available the data from the W-graph of the group which are required in the computation, in a convenient way. The idea is that d_edge lists for each generator s, and each z in the group s.t. sz < z, the set of x s.t. (z,x) is an edge in the graph, and sx > x; these are the terms that occur in the formulas for c_s.c_x. The list d_coeff contains the corresponding mu-coefficient. The point is to do these extractions once and for all, and record them here, instead of having to run zillions of times through the edge-lists of the graph; the memory cost is very reasonable. ******************************************************************************/ namespace { GraphData::GraphData(const WGraph& X, const Rank& l) /* Constructs the edge and coefficient lists for each generator, as explained in the introduction to this section. */ { d_size = X.size(); // allocate lists d_edge.setSize(l); d_coeff.setSize(l); for (Generator s = 0; s < l; ++s) { (d_edge)[s].setSize(d_size); (d_coeff)[s].setSize(d_size); } // fill lists for (CoxNbr x = 0; x < X.size(); ++x) { const EdgeList& e = X.edge(x); const CoeffList& c = X.coeffList(x); LFlags fx = X.descent(x); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr z = e[j]; LFlags fz = X.descent(z); // look at the generators s.t. sx < x and sz > z for (LFlags f = fx & ~fz; f; f &= f-1) { Generator s = firstBit(f); d_edge[s][z].append(x); d_coeff[s][z].append(c[j]); } } } } }; /***************************************************************************** Chapter III -- The PolTable class. This is another helper class for the computation, containing the data for the management of the polynomial table. This is a huge matrix of polynomial pointers, one for each pair of elements in the group, contained in d_list; the actual polynomials are stored in d_tree, a binary tree which makes it easy to search for them. One important fact is that zero polynomials are ignored, i.e. correspond to "empty" entries in the table (zero-pointers). ******************************************************************************/ namespace { PolTable::PolTable (const Ulong& m, const Ulong& n) /* Allocates an empty (i.e., zero-pointer initialized) table of size size.size. The idea is to allocate the memory in a single large block, and let each row point to the appropriate offset. This is done primarily to optimize the setZero member function. Believe it or not, setting each individual row to zero made this into the dominant function of the program! */ { d_data.setSize(m*n); d_row.setSize(m); d_row[0] = &d_data[0]; for (Ulong j = 1; j < m; ++j) d_row[j] = d_row[j-1] + n; } PolTable::PolTable (const BitMap& b) /* Does a "sparse" allocation of the table, allocating rows only for the elements flagged by the bitmap. This is used for the computation of a single product c_x.c_y; only products c_u.c_y for u <= x are required in the inductive computation. */ { Ulong m = b.bitCount(); Ulong n = b.size(); d_data.setSize(m*n); d_row.setSize(n); BitMap::Iterator b_end = b.end(); Ulong j = 0; for (BitMap::Iterator i = b.begin(); i != b_end; ++i, ++j) d_row[*i] = &d_data[j*n]; } }; /***************************************************************************** Chapter IV -- The PolTree class This is a small modification of a binary tree, where the size of the allocations is recorded as we go. ******************************************************************************/ namespace { Pol* PolTree::find(const Pol& p) /* Looks up a polynomial in the tree, adding it if it is not already there. */ { Ulong prev_size = size(); Pol* r = search::BinaryTree::find(p); if (size() > prev_size) { // new polynomial found // check unimodality if (!isUnimodal(p)) { // polynomial is not unimodal! // write error message FILE* errorFile = fopen("error_log","a"); fprintf(errorFile,"\nnon-unimodal polynomial found :\n\n"); fclose(errorFile); } // update maxCoeff for (Ulong i = 0; i <= p.deg(); ++i) { if (p[i] > d_maxCoeff) d_maxCoeff = p[i]; } } return r; } void PolTree::reset() /* Frees the memory for the tree part, while retaining the maxCoeff information. */ { delete d_root; d_root = 0; d_size = 0; } }; /***************************************************************************** Chapter V -- Functions for the positivity check. ******************************************************************************/ namespace { void addSimpleTerm(List& a, const CoxNbr& z, const Pol& q) /* Deals with the case where we have to add (1/v+v)*q to a. In fact, we write only the positive part of the polynomial; this has either all even or all odd terms. Then the effect of multiplying by (1/v+v) is as follows : (a) degree increases by one (b) if j > 1, the j-th coefficient of the new polynomial is the sum of the two surrounding coefficients in the old one; (c) when the degree is even, the 0-th coefficient of the new polynomial is twice the 1-st coefficient of the old one. NOTE : we must be very careful to check for overflow. It so happens that there is in fact no overflow on a 32-bit computer for H4, but it's not so far off. */ { Pol& p = a[z]; if (p.isZero() || (p.deg() < q.deg()+1)) p.setDeg(q.deg()+1); if (q.deg()%2) { // odd degree for q if (p[0] > (COEFF_MAX-2*q[1])) goto overflow; p[0] += 2*q[1]; for (Ulong j = 2; j < q.deg(); j += 2) { if (p[j] > (COEFF_MAX-q[j-1])) goto overflow; p[j] += q[j-1]; if (p[j] > (COEFF_MAX-q[j+1])) goto overflow; p[j] += q[j+1]; } if (p[q.deg()+1] > (COEFF_MAX-q[q.deg()])) goto overflow; p[q.deg()+1] += q[q.deg()]; } else { // even degree for q for (Ulong j = 1; j < q.deg(); j += 2) { if (p[j] > (COEFF_MAX-q[j-1])) goto overflow; p[j] += q[j-1]; if (p[j] > (COEFF_MAX-q[j+1])) goto overflow; p[j] += q[j+1]; } if (p[q.deg()+1] > (COEFF_MAX-q[q.deg()])) goto overflow; p[q.deg()+1] += q[q.deg()]; } return; overflow: FILE* errorFile = fopen("error_log","a"); fprintf(errorFile,"\noverflow in addSimpleTerm\n\n"); fclose(errorFile); return; } void addTerm(List& a, const List& e, const List& c, const Pol& pol) /* Adds to a, representing the coefficients of an element of the Hecke algebra in the c-basis, pol times the element represented in sparse form by e and c. */ { for (Ulong j = 0; j < e.size(); ++j) { if (c[j] == 1) // this happens allmost all the time // call an optimized version safeAdd(a[e[j]],pol); else { safeAdd(a[e[j]],pol,c[j]); } } return; } void extendTable(PolTable& pt, const WGraph& X, const SchubertContext& p, const CoxNbr& x, const GraphData& gd) /* Fills in the row for x in b, assuming that previous rows have been filled already. Uses the formula */ { static List a(0); a.setSize(gd.size()); LFlags f = X.descent(x); // f holds the left descent set of x Generator s = lastBit(f); // largest descent generator #if 0 Generator s = firstBit(f); // smallest descent generator #endif CoxNbr sx = p.lshift(x,s); // compute c_s.c_sx.c_y for (CoxNbr z = 0; z < gd.size(); ++z) { const Pol* pol_ptr = pt(sx,z); // this is b_{sx,y,z} if (pol_ptr == 0) continue; if (X.descent(z) & lmask[s]) // a[z] += (v+v^{-1})b_{sx,y,z} addSimpleTerm(a,z,*pol_ptr); else { // c_s.c_z is computed from the W-graph using the data in gd const List& e = gd.edge(s,z); const List& c = gd.coeff(s,z); addTerm(a,e,c,*pol_ptr); } } // subtract terms mu(z,sx)c_z.c_y const List& e = gd.edge(s,sx); const List& c = gd.coeff(s,sx); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr z = e[j]; if (z == x) continue; subtract(a,pt.row(z),c[j]); } // write row to table writeRow(a,pt,x); return; } bool fillTable(PolTable& pt, const WGraph& X, const SchubertContext& p, const CoxNbr& y, const GraphData& gd) /* This function fills in the table of coefficients b_{x,y,z} for fixed y, i.e., it computes the various c_x.c_y when x runs through the group. It works by induction on the length of x, by successive calls to extendTable (see the introduction to this module for more details.) */ { // initialize row 0 pt.write(one(),0,y); // the others are initialized to 0 already // build table for (CoxNbr x = 1; x < gd.size(); ++x) extendTable(pt,X,p,x,gd); return true; } bool isSmaller(const kl::KLPol& p, const kl::KLPol& q) /* Returns true if q-p has nonnegative coefficients; false otherwise. It is assumed that p and q are non-zero. */ { if (p.deg() > q.deg()) return false; for (Ulong j = 0; j <= p.deg(); ++j) { if (p[j] > q[j]) return false; } return true; } bool isUnimodal(const Pol& pol) /* Tells if the polynomial pol is unimodal (in fact, we are passed the second half of the polynomial; so the check here is to see if p[j] <= p[j-1] for all j >= 1.) */ { for (Degree j = pol.deg()%2 + 2; j <= pol.deg(); j += 2) if (pol[j] > pol[j-2]) return false; return true; } const Pol& one() /* Returns the constant polynomial equal to one (this makes for simpler code elsewhere.) */ { static Pol pol(1,Pol::const_tag()); return pol; } void prettyPrint(FILE* file, const Pol& pol, const Degree& parity) /* Pretty-prints the polynomial onto file, with the appropriate degree-expansion according to parity. */ { static Pol p(0); p.setZero(); p.setDeg(2*pol.deg()+parity); for (Degree j = 0; j <= pol.deg(); ++j) p[2*j+parity] = pol[j]; print(file,p,"v"); return; } void printRow(FILE* file, const Pol** a, FiniteCoxGroup* W) /* Prints out a row in the coefficient table. This corresponds to the expression of c_x.c_y for some x and y. NOTE: as always, only the "positive-degree-half" of the polynomials are actually printed; the other half is symmetric. */ { bool first = true; // tells if we are printing the first non-zero coefficient for (Ulong i = 0; i < W->order(); ++i) { if (a[i] == 0) continue; // print a "+" only if this is not the first term if (first) first = false; else fprintf(file,"+"); // print output in the form (polynomial_in_v)c(group_element) fprintf(file,"("); print(file,*(a[i]),"v"); fprintf(file,")c(",i); W->print(file,i); fprintf(file,")",i); } return; } void printTable(FILE* file, const PolTable& pt, FiniteCoxGroup* W) /* Prints the full table of polynomials, for a given y, by successive calls to printRow. */ { for (Ulong j = 0; j < pt.size(); ++j) { bool first = true; const Pol** bpp = pt.row(j); W->print(file,j); fprintf(file,":"); printRow(file,bpp,W); fprintf(file,"\n"); } return; } void safeAdd(Pol& p, const Pol& q) /* Adds q to p while looking out for overflow. Makes a note in error_log if overflow is seen. */ { if (p.isZero()) { p = q; return; } if (p.deg() < q.deg()) p.setDeg(q.deg()); for (Ulong j = 0; j <= q.deg(); ++j) { if (p[j] > (COEFF_MAX-q[j])) goto overflow; p[j] += q[j]; } return; overflow: FILE* errorFile = fopen("error_log","a"); fprintf(errorFile,"\noverflow in addTerm\n\n"); fclose(errorFile); return; } void safeAdd(Pol& p, const Pol& q, const KLCoeff& c) /* Adds c*q to p while looking out for overflow. Makes a note in error_log if overflow is seen. */ { if (p.isZero() || (p.deg() < q.deg())) p.setDeg(q.deg()); for (Ulong j = 0; j <= q.deg(); ++j) { if (q[j] > COEFF_MAX/c) goto overflow; if (p[j] > (COEFF_MAX-c*q[j])) goto overflow; p[j] += c*q[j]; } return; overflow: FILE* errorFile = fopen("error_log","a"); fprintf(errorFile,"\noverflow in addTerm\n\n"); fclose(errorFile); return; } void safeSubtract(Pol& p, const Pol& q) /* Subtracts q from p while looking out for overflow. Makes a note in error_log if underflow is seen. NOTE : it is assumed that q is non-zero. */ { if (p.isZero() || (p.deg() < q.deg())) { print(stderr,p,"v"); printf("\n"); print(stderr,q,"v"); printf("\n"); goto underflow; } for (Ulong j = 0; j <= q.deg(); ++j) { if (p[j] < q[j]) goto underflow; p[j] -= q[j]; } p.reduceDeg(); return; underflow: FILE* errorFile = fopen("error_log","a"); fprintf(errorFile,"\nunderflow in subtract\n\n"); fclose(errorFile); return; } void safeSubtract(Pol& p, const Pol& q, const KLCoeff& c) /* Subtracts c*q to p while looking out for underflow. Makes a note in error_log if underflow is seen. NOTE : it is assumed that q is non-zero! */ { if (p.isZero() || (p.deg() < q.deg())) goto underflow; for (Ulong j = 0; j <= q.deg(); ++j) { if (q[j] > COEFF_MAX/c) goto underflow; if (p[j] < c*q[j]) goto underflow; p[j] -= c*q[j]; } p.reduceDeg(); return; underflow: FILE* errorFile = fopen("error_log","a"); fprintf(errorFile,"\nunderflow in addTerm\n\n"); fclose(errorFile); return; } void subtract(List& a, const Pol** b, const KLCoeff& c) /* Subtracts b*c from a; */ { if (c > 1) { for (Ulong j = 0; j < a.size(); ++j) { if (b[j] == 0) continue; safeSubtract(a[j],*(b[j]),c); } } else { for (Ulong j = 0; j < a.size(); ++j) { if (b[j] == 0) continue; safeSubtract(a[j],*(b[j])); } } return; } void writeRow(List& a, PolTable& pt, const Ulong& i) /* Writes down the row a in the table. It sets the polynomials in a to zero as it reads them. */ { for (Ulong j = 0; j < a.size(); ++j) { if (a[j].isZero()) continue; pt.write(a[j],i,j); a[j].setZero(); } return; } }; positivity_final/special.h0000600000175000017500000000073110011171251017411 0ustar duclouxducloux00000000000000/* This is special.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef SPECIAL_H /* guard against multiple inclusions */ #define SPECIAL_H #include "globals.h" namespace special { using namespace globals; }; /******** function declarations *********************************************/ #include "commands.h" namespace special { void addSpecialCommands(commands::CommandTree* tree); }; #endif positivity_final/stack.cpp0000600000175000017500000000000010011171251017416 0ustar duclouxducloux00000000000000positivity_final/stack.h0000600000175000017500000000333010115633334017106 0ustar duclouxducloux00000000000000/* This is stack.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef STACK_H /* guard against multiple inclusions */ #define STACK_H #include "globals.h" namespace stack { using namespace globals; }; /* class declarations */ namespace stack { template class Fifo; template class Stack; }; /******* class definitions *************************************************/ #include "list.h" namespace stack { using namespace list; }; namespace stack { template class Fifo { private: List d_list; Ulong d_first; Ulong d_last; Ulong d_size; public: /* constructors and destructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(Fifo));} Fifo(); ~Fifo() {}; /* modifiers */ const T& pop(); void push(const T&); /* accessors */ Ulong size() const; const T& top() const; }; template class Stack { private: List d_list; public: /* constructors and destructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(Stack));} Stack(); ~Stack(); /* modifiers */ const T* pop(); void push(const T&); /* accessors */ Ulong size() const; const T& top() const; }; }; /******** Inline implementations ******************************************/ namespace stack { template inline Ulong Stack::size() const {return d_list.size();} template inline const T& Stack::top() const {return d_list[d_list.size()-1];} template inline Ulong Fifo::size() const {return d_size;} template inline const T& Fifo::top() const {return d_list[d_first];} }; #include "stack.hpp" #endif positivity_final/stack.hpp0000600000175000017500000000703710011171251017444 0ustar duclouxducloux00000000000000/* This is stack.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "error.h" /**************************************************************************** This module contains an elementary implementation of a pushdown stack, using our List type, so that the size of the stack is unbounded. In addition to push and pop, we provide a function top to get the value of the top element of the stack, without popping it (defined inline.) It also contains an implementation of a Fifo list, implemented as a circular list. ****************************************************************************/ /**************************************************************************** Chapter I -- Yhe Fifo class First-in, first-out lists are implemented here as circular lists. There are two pointers first and last, for the first and last element in the list. When last reaches list.size(), it loops to zero; first is increased on deletion of an element. More room is required when last+1=first mod size; then more room is obtained in the List, and the part ahead of first is pushed to the end. The following functions are defined : - Fifo() : constructor; - push(object) : push an object on the list; - pop() : pop the list; - top() : peak at the top element (the one that would be popped); (inlined) - size() : number of elements in list; (inlined) ****************************************************************************/ namespace stack { template Fifo::Fifo() : d_list(0), d_first(0), d_last(~0L), d_size(0) {} template void Fifo::push(const T& object) /* Pushes an object on the list, enlarging the list if necessary. */ { d_last++; if (d_last == d_first) { /* we need more space */ d_list.setSize(d_list.size()+1); if (d_first < (d_list.size()-1)) { /* move up */ d_list.setData(d_list.ptr()+d_first,d_first+1,d_list.size()-d_first-1); } d_first++; } else if (d_last == d_list.size()) /* wrap around */ d_last = 0; d_list[d_last] = object; d_size++; return; } template const T& Fifo::pop() /* Pops the list; it is assumed that the user has checked for non-emptyness. */ { if (d_first == d_list.size()) d_first = 0; const T& result = d_list[d_first]; d_size--; if (d_size == 0) { /* reset an empty list */ d_first = d_list.size(); d_last = ~0L; } else d_first++; return result; } }; /**************************************************************************** Chapter II -- The Stack class. This section contains the definition of the functions in the Stack class. The following functions are defined : - Stack(); - ~Stack(); - push(object) : push an object on the stack, enlarging if necessary; - pop() : pops the stack, setting an error if empty; ****************************************************************************/ namespace stack { template Stack::Stack() {} template Stack::~Stack() /* Destructing the components is enough. */ {} template void Stack::push(const T& object) /* Assumes that copy constructor is defined for class T. */ { d_list.append(object); } template const T* Stack::pop() /* Pops the stack, returning the address of the corresponding object. Returns 0 if the stack is empty. */ { if (d_list.size() != 0) { d_list.setSize(d_list.size()-1); return &d_list[d_list.size()]; } return 0; } }; positivity_final/transducer.cpp0000600000175000017500000003634510011171251020510 0ustar duclouxducloux00000000000000/* This is transducer.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "transducer.h" #include "bits.h" #include "error.h" namespace transducer { using namespace error; using namespace transducer; }; /******** local definitions *************************************************/ namespace { using namespace transducer; ParNbr dihedralMin(SubQuotient *X, ParNbr y, Generator s, Generator t); ParNbr dihedralShift(SubQuotient *X, ParNbr y, Generator s, Generator t, Ulong c); }; /**************************************************************************** This file contains code for handling the basic group operations using the transducer representation, as described in my paper in J. of Symb. Comp. 27 (1999), pp. 311--324. This is certainly the preferred way for handling finite Coxeter groups : it is compact, simple and extremely fast (linear time in the length of the input word.) Also, using the array representation for group elements, it will work nicely for *all* finite Coxeter groups of rank <= 255. In fact, partially defined automata can be constructed for any group, and this is more or less equivalent to the construction of the parabolic shift tables that we need for the kl-computations. So we should set everything up for an arbitrary Coxeter group; there will be a partially defined automaton for every subquotient X_j, 1 <= j <= n. The domain of this automaton should be a decreasing subset of X_j. Correspondingly, there will be an array representation for a certain subset of the group (the product of the domains). ****************************************************************************/ /**************************************************************************** Chapter I -- The FiltrationTerm class. This section provides the definitions of the functions in the FiltrationTerm class : - FiltrationTerm(CoxGraph&, Rank, FiltrationTerm*); - fillNormalPieces() : fills the array of normal forms; ****************************************************************************/ namespace transducer { FiltrationTerm::FiltrationTerm(CoxGraph& G, Rank l, FiltrationTerm* p) :d_next(p) /* Constructs the l-th term of the filtration of the group of graph G. */ { d_X = new SubQuotient(G,l); d_np.setSize(1); new(d_np.ptr()) CoxWord(0); } FiltrationTerm::~FiltrationTerm() /* Although in principle a transducer is a linked list, it is safer to traverse it explicitly and delete each term. Hence we don't delete next. */ { delete d_X; } void FiltrationTerm::fillNormalPieces() /* This function fills in the d_np array; it is a private member because it needs access but is only used in the initialization. We use the fact that the enumeration of the elements of the subquotient is in ShortLex order (it would have been more efficient to construct the normal pieces together with the enumeration, but it is better to keep the two things separate.) Therefore, we look for the "steepest descent" from any given x. */ { Ulong old_size = d_np.size(); /* is always > 0 */ d_np.setSize(size()); for (Ulong j = old_size; j < size(); ++j) new(d_np.ptr()+j) CoxWord(length(j)); for (ParNbr x = old_size; x < size(); ++x) { ParNbr y = x; Generator t = undef_generator; for (Generator s = 0; s < rank(); ++s) { if (shift(x,s) < y) { /* this s is better than what we had */ y = shift(x,s); t = s; } } d_np[x] = d_np[y]; d_np[x][length(y)] = t+1; d_np[x].setLength(length(x)); } return; } }; /**************************************************************************** Chapter II -- The SubQuotient class. This section provides the definitions of the functions in the SubQuotient class : - SubQuotient(CoxGraph&, Rank); - extend(ParNbr, Generator) : extends the transducer; - fill(CoxGraph&) : fills in the full transducer; - schubertClosure(SubSet,ParNbr) : extracts an interval from the origin; ****************************************************************************/ /**************************************************************************** We deviate slightly from the approach taken in previous versions of Coxeter, in the sense that generators are now consistently represented by elements in [0,rank[, except in coxwords where they are translated by one, so that coxwords may be manipulated as strings. Also, we take advantage from the fact that signed arithmetic is consistently implemented for unsigned quantities (i.e., -1 is guaranteed to be the largest representable number, etc, ...) to have all table entries be unsigned, still reserving the uppermost values for the negatives of the generators, and the special value undef_parnbr. The following functions are provided : - schubertClosure(V,x) : returns the subinterval [e,x] in the parabolic subquotient determined by V. ****************************************************************************/ namespace transducer { SubQuotient::SubQuotient(CoxGraph& G, Rank l) :d_rank(l),d_size(1),d_graph(G),d_shift(l),d_length(1) /* This function makes the l-th subquotient in the group corresponding to G and initializes its first node. */ { d_shift.setSize(l); for (Generator s = 0; s < l-1; ++s) shiftref(0,s) = undef_parnbr + s+1; shiftref(0,l-1) = undef_parnbr; return; } SubQuotient::~SubQuotient() /* Automatic destruction of the components is enough here. */ {} /******* manipulators *****************************************************/ ParNbr SubQuotient::extend(ParNbr x, Generator s) /* The program always maintains the automata in the following state : (a) the domain fo the automaton is a decreasing subset of X_j, originally {e} = {0}; the enumeration is increasing w.r.t. Bruhat order (b) for each x in the domain, all x[s] for which either xs is in the domain, or xs = tx, are filled in; so the value undef_parnbr means that xs is an element of X_j, not in the domain. This function realizes the central step in the automaton construction. Given an element x in the automaton of level l, and a generator s for which x[s] is currently undef_parnbr (which means that the element is not in the domain of the automaton), we enlarge the automaton to include the whole of [e,x]s (this is to ensure that the domain will always be a decreasing subset in the parabolic quotient.) This process involves three stages : - extract the interval [e,x] from the domain : this can be done using the known part of the automaton, and a reduced expression for x (which can also be found from the known part); - find the size of the enlargement --- this is trivial, they are the z <= x for which z[s] is undef_parnbr; - construct the enlargement proper (see below); For the third step, we proceed taking the new elements in order. For each new element zs, and each t != s, we can determine if xst > xs or xst < xs, just by applying t,s,t, ... to x, and m = m_{s,t} : if xs is maximal in its right coset under , then xst < xs, and xst > xs otherwise. So this already gives us the right descent set; moreover we can find xst by applying more t,s,t, ... ubtil we get to the appropriate length. This fills in all the downwards shifts from xs, hence all the upwwards shifts that become defined from the addition of the new elements, and stay within X_l. The shifts that are not yet filled in correspond to either undef_parnbr, or cases where xst = uxs for some u < l-1. Then xsts = ux, and in particular xsts < xst. Again this can be decided from applying t,s,t, ... to x, and the resulting xsts can be computed. So we can decide in all cases. */ { if (shift(x,s) != undef_parnbr) /* no need to extend */ return shift(x,s); if (length(x) == LENGTH_MAX) /* overflow */ { ERRNO = LENGTH_OVERFLOW; return undef_parnbr; } static SubSet Q; schubertClosure(Q,x); Ulong c = 0; for (Ulong j = 0; j < Q.size(); ++j) /* count new elements */ if (shift(Q[j],s) == undef_parnbr) ++c; if (c > PARNBR_MAX - d_size) { /* overflow --- quite possible! */ ERRNO = PARNBR_OVERFLOW; return undef_parnbr; } /* resize */ d_shift.setSize(d_rank*(d_size+c)); d_length.setSize(d_size+c); /* fill in shifts by s */ Ulong prev_size = d_size; for (Ulong j = 0; j < Q.size(); ++j) if (shift(Q[j],s) == undef_parnbr) { shiftref(Q[j],s) = d_size; shiftref(d_size,s) = Q[j]; lengthref(d_size) = length(Q[j]) + 1; ++d_size; } /* fill in remaining shifts */ for (ParNbr z = prev_size; z < d_size; ++z) { for (Generator t = 0; t < d_rank; ++t) { if (t == s) continue; shiftref(z,t) = undef_parnbr; /* initialzation */ CoxEntry m = d_graph.M(s,t); if (m == 0) continue; ParNbr y = dihedralMin(this,z,s,t); Length d = length(z) - length(y); if (d < m-1) /* zt > z, no transduction */ continue; if (d == m) { /* zt < z */ if (m%2) y = dihedralShift(this,y,t,s,m-1); else y = dihedralShift(this,y,s,t,m-1); shiftref(z,t) = y; shiftref(y,t) = z; continue; } /* now d == m-1 */ if (m%2) y = dihedralShift(this,y,s,t,m-1); else y = dihedralShift(this,y,t,s,m-1); if (y > undef_parnbr) /* zt = uz */ shiftref(z,t) = y; } } return size()-1; } void SubQuotient::fill(const CoxGraph& G) /* This function fills the subquotient of rank l for the group defined by G. It will loop indefinitely if the subquotient is not finite! The Coxeter graph really only comes in because it currently holds the Coxeter matrix. Notice that the elements are actually constructed in ShortLex order. Indeed, when a new element is put on the list, in the form x.s, all extensions of all x' < x have already been considered; so the new element doesn't have a descent on any smaller element. NOTE : some explanations about the algorithm should go here! */ { for (Ulong x = 0; x < d_size; ++x) { /* find all extensions of x */ for (Generator s = 0; s < rank(); ++s) { if (shift(x,s) == undef_parnbr) { /* extend */ d_shift.setSize(d_rank*(d_size+1)); d_length.setSize(d_size+1); shiftref(d_size,s) = x; shiftref(x,s) = d_size; lengthref(d_size) = length(x) + 1; for (Generator t = 0; t < rank(); t++) { /* find shifts */ if (t == s) continue; /* next t */ shiftref(d_size,t) = undef_parnbr; CoxEntry m = G.M(s,t); ParNbr y = dihedralMin(this,d_size,s,t); Length d = length(d_size) - length(y); if (d < m-1) continue; /* next t */ if (d == m) { if (m%2) y = dihedralShift(this,y,t,s,m-1); else y = dihedralShift(this,y,s,t,m-1); shiftref(d_size,t) = y; shiftref(y,t) = d_size; continue; /* next t */ } /* now d == m-1 */ if (m%2) y = dihedralShift(this,y,s,t,m-1); else y = dihedralShift(this,y,t,s,m-1); if (y > undef_parnbr) /* y holds transduction value */ shiftref(d_size,t) = y; } ++d_size; } } } return; } /******* accessors *********************************************************/ Generator SubQuotient::firstDescent(const ParNbr& x) const /* Returns the smallest s such that x.s < x, rank() if there is no such s, i.e., if x = 0; */ { for (Generator s = 0; s < rank(); ++s) if (shift(x,s) < x) return s; return rank(); } void SubQuotient::schubertClosure(SubSet& Q, ParNbr x) /* This function returns in Q the set of all z in X such that z <= x in the Bruhat order, resizing Q if necessary. */ { static bits::BitMap f; /* should become bitmap type */ static CoxWord g; f.setSize(size()); f.reset(); f.setBit(0); Q.setSize(1); Q[0] = 0; Ulong prev_size = 1; reduced(g,x); for (Ulong j = 0; j < g.length(); ++j) { Ulong c = 0; Generator s = g[j]-1; for (Ulong z = 0; z < prev_size; ++z) { /* count new elements */ if (shift(z,s) > undef_parnbr) /* undef_parnbr is impossible */ continue; if (!f.getBit(shift(z,s))) ++c; } Q.setSize(Q.size() + c); /* should become Q += c ? */ ParNbr firstfree = prev_size; for (Ulong z = 0; z < prev_size; ++z) { if (shift(z,s) > undef_parnbr) continue; if (!f.getBit(shift(z,s))) { /* add new element */ f.setBit(shift(z,s)); Q[firstfree] = shift(z,s); ++firstfree; } } prev_size += c; } return; } CoxWord& SubQuotient::reduced(CoxWord& g, ParNbr x) const { Length p = length(x); g.setLength(p); for (Ulong j = 1; x; ++j) { /* take off last generator */ Generator s = firstDescent(x); g[p-j] = s + 1; x = shift(x,s); } return g; } }; /**************************************************************************** Chapter III -- The Transducer class. This section provides the definitions of the functions in the Transducer class : - Transducer(CoxGraph&); - ~Transducer(); ****************************************************************************/ namespace transducer { Transducer::Transducer(CoxGraph& G):d_filtration(G.rank()) { Rank l = G.rank(); for (Rank j = 0; j < l-1; j++) new(d_filtration.ptr()+j) FiltrationTerm(G,l-j,d_filtration.ptr()+j+1); new(d_filtration.ptr() + l-1) FiltrationTerm(G,1); d_filtration.setSize(l); } Transducer::~Transducer() /* The list destructor will destruct each term of the transducer. */ {} }; /**************************************************************************** Chapter VI -- Auxiliary functions. This section regroups some auxiliary functions, used in the automata construction. The functions provided are : - dihedralMin(V,y,s,t) : returns the minimal element in the right coset of y for the dihedral subgroup generated by s and t; - dihedralShift(V,y,s,t,c) : returns the result of applying a string of c generators alternately equal to s and t to y; ****************************************************************************/ namespace { ParNbr dihedralMin(SubQuotient* X, ParNbr y, Generator s, Generator t) /* Given a legal element y in X, and two generators s and t, returns the minimal element in the right coset of y under the parabolic subgroup generated by s and t (this will always lie in the domain of the automaton, and is computable from the automaton information). The result is found from simply applying alternatively s and t until the length doesn't go down anymore. */ { Generator u; if (X->shift(y,s) >= y) u = t; else u = s; while(1) { if (X->shift(y,u) >= y) return y; else y = X->shift(y,u); if (u == s) u = t; else u = s; } } ParNbr dihedralShift(SubQuotient* X, ParNbr y, Generator s, Generator t, Ulong c) /* Given a legal element y in the automaton for V, and two generators s,t <= rank(V), this function returns the result of applying the string stst... (c terms) to y on the right, if this is a legal element in P. If undfined is encountered, the return value is undef_parnbr. If a generator (i.e., a value > undef_parnbr) is encountered, that value is returned. */ { Generator u = s; for (Ulong j = 0; j < c; j++) { if (X->shift(y,u) >= undef_parnbr) return X->shift(y,u); y = X->shift(y,u); if (u == s) u = t; else u = s; } return y; } }; positivity_final/transducer.h0000600000175000017500000001210410012716255020152 0ustar duclouxducloux00000000000000/* This is transducer.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef TRANSDUCER_H /* guarantee single inclusion */ #define TRANSDUCER_H #include "globals.h" namespace transducer { using namespace globals; }; /******** type declarations *************************************************/ namespace transducer { class FiltrationTerm; class SubQuotient; class Transducer; }; /******** constants *********************************************************/ #include "coxtypes.h" namespace transducer { using namespace coxtypes; }; namespace transducer { static const ParNbr undef_parnbr = PARNBR_MAX + 1; }; /******** type definitions **************************************************/ #include "graph.h" #include "list.h" #include "memory.h" namespace transducer { using namespace list; using namespace memory; using namespace graph; }; class transducer::SubQuotient { private: /* typedef in class scope */ typedef List SubSet; /* data */ Rank d_rank; Ulong d_size; CoxGraph& d_graph; List d_shift; List d_length; ParNbr& shiftref(ParNbr x, Generator s) {return d_shift[x*d_rank+s];} Length& lengthref(ParNbr x) {return d_length[x];} public: /* constructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(SubQuotient));} SubQuotient(CoxGraph& G, Rank l); ~SubQuotient(); /* manipulators */ ParNbr extend(ParNbr x, Generator s); void fill(const CoxGraph& G); /* accessors */ Generator firstDescent(const ParNbr& x) const; Length length(const ParNbr& x) const; /* inlined */ Rank rank() const; /* inlined */ CoxWord& reduced(CoxWord& g, ParNbr x) const; ParNbr shift(const ParNbr& x, const Generator& s) const; /* inlined */ Ulong size() const; /* inlined */ void schubertClosure(SubSet& Q, ParNbr x); }; class transducer::FiltrationTerm { SubQuotient *d_X; FiltrationTerm *d_next; List d_np; void fillNormalPieces(); public: /* constructors */ void operator delete(void* ptr) {return arena().free(ptr,sizeof(FiltrationTerm));} FiltrationTerm() {}; FiltrationTerm(CoxGraph& G, Rank l, FiltrationTerm* p = 0); ~FiltrationTerm(); /* manipulators */ ParNbr extend(const ParNbr& x, const Generator& s); /* inlined */ void fill(const CoxGraph& G); /* inlined */ /* accessors */ CoxLetter firstDescent (const ParNbr& x) const; /* inlined */ Length length(const ParNbr& x) const; /* inlined */ FiltrationTerm *next() const; /* inlined */ const CoxWord& np(const ParNbr& x) const; /* inlined */ Rank rank() const; /* inlined */ CoxWord& reduced(CoxWord& g, ParNbr x) const; /* inlined */ ParNbr shift(const ParNbr& x, const Generator& s) const; /* inlined */ Ulong size() const; /* inlined */ }; class transducer::Transducer { private: List d_filtration; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(Transducer));} Transducer(CoxGraph& G); ~Transducer(); /* manipulators */ FiltrationTerm* transducer(const Rank& l) {return d_filtration.ptr()+l;} /* accessors */ const FiltrationTerm* transducer(const Rank& l) const; }; /******** inline implementations ********************************************/ namespace transducer { /* SubQuotient */ inline Length SubQuotient::length(const ParNbr& x) const {return d_length[x];} inline Rank SubQuotient::rank() const {return d_rank;} inline ParNbr SubQuotient::shift(const ParNbr& x, const Generator& s) const {return d_shift[x*d_rank+s];} inline Ulong SubQuotient::size() const {return d_size;} /* FiltrationTerm */ inline ParNbr FiltrationTerm::extend(const ParNbr& x, const Generator& s) {return d_X->extend(x,s);} inline void FiltrationTerm::fill(const CoxGraph& G) {d_X->fill(G); fillNormalPieces();} inline CoxLetter FiltrationTerm::firstDescent (const ParNbr& x) const {return d_X->firstDescent(x);} inline Length FiltrationTerm::length(const ParNbr& x) const {return d_X->length(x);} inline FiltrationTerm* FiltrationTerm::next() const {return d_next;} inline const CoxWord& FiltrationTerm::np(const ParNbr& x) const {return d_np[x];} inline Rank FiltrationTerm::rank() const {return d_X->rank();} inline CoxWord& FiltrationTerm::reduced(CoxWord& g, ParNbr x) const {return d_X->reduced(g,x);} inline ParNbr FiltrationTerm::shift(const ParNbr& x, const Generator& s) const {return d_X->shift(x,s);} inline Ulong FiltrationTerm::size() const {return d_X->size();} /* Transducer */ inline const FiltrationTerm* Transducer::transducer(const Rank& l) const {return d_filtration.ptr()+l;} }; #endif positivity_final/type.cpp0000600000175000017500000000537110011171251017312 0ustar duclouxducloux00000000000000/* This is type.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "type.h" namespace { using namespace type; const char* affinetypes ="abcdefg"; const char *finitetypes = "ABCDEFGHI"; }; /**************************************************************************** Chapter I -- The Type class. For now, a type contains just a name. ****************************************************************************/ namespace type { Type::Type():d_name("") /* Default constructor; yields the undefined type. */ {} Type::Type(const char* str):d_name(str) /* Makes the type with name str. */ {} Type::~Type() /* Just destroy the corresponding String. */ {} }; /***************************************************************************** Chapter II -- Type recognition. This section contains the definitions of the type-recognition functions declared in this module. The following functions are defined : - isAffineType(const Type&) : recognizes affine Coxeter groups; - isFiniteType(const Type&) : recognizes finite Coxeter groups; - isTypeA(const Type&) : recognizes type A; - isTypeB(const Type&) : recognizes type B; - isTypeD(const Type&) : recognizes type D; *****************************************************************************/ namespace type { bool isAffineType(const Type& x) /* Recognizes the type of an affine group. This function defines the class of groups that will be treated as affine groups in this program; the i/o setup is flexible enough that there is no reason that an affine group should be entered otherwise. */ { if (strchr(affinetypes,x[0]) == NULL) return false; return true; } bool isFiniteType(const Type& type) /* Recognizes the type of a finite group. Non-irreducible types are allowed; they are words in the irreducible types. This function defines the class of groups that will be treated as finite groups in this program; the i/o setup is flexible enough that there is no reason that a finite group should be entered otherwise. */ { for (Ulong j = 0; j < type.name().length(); ++j) { if (strchr(finitetypes,type[j]) == NULL) return false; } return true; } bool isTypeA(const Type& type) /* Recognizes if the group is of type A; it is assumed that isFiniteType has already been checked. */ { return type[0] == 'A'; } bool isTypeB(const Type& type) /* Recognizes if the group is of type B; it is assumed that isFiniteType has already been checked. */ { return type[0] == 'B'; } bool isTypeD(const Type& type) /* Recognizes if the group is of type D; it is assumed that isFiniteType has already been checked. */ { return type[0] == 'D'; } }; positivity_final/type.h0000600000175000017500000000306010011171251016750 0ustar duclouxducloux00000000000000/* This is type.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef TYPE_H /* guard against multiple inclusions */ #define TYPE_H #include "globals.h" namespace type { using namespace globals; }; /******** type declarations *************************************************/ namespace type { class Type; }; /******** function declarations *********************************************/ namespace type { bool isAffineType(const Type& type); bool isFiniteType(const Type& type); bool isTypeA(const Type& type); bool isTypeB(const Type& type); bool isTypeD(const Type& type); } /******** type definitions **************************************************/ #include "io.h" namespace type { using namespace io; }; namespace type { class Type { private: String d_name; public: // constructors and destructors void operator delete(void* ptr) {return arena().free(ptr,sizeof(Type));} Type(); Type(const char*); ~Type(); // accessors const char& operator[] (const Ulong& j) const; const String& name() const; // manipulators char& operator[] (const Ulong& j); String& name(); }; const Type undef_type(""); }; /******** inlined definitions **********************************************/ namespace type { inline const char& Type::operator[] (const Ulong& j) const {return d_name[j];} inline const String& Type::name() const {return d_name;} inline char& Type::operator[] (const Ulong& j) {return d_name[j];} inline String& Type::name() {return d_name;} }; #endif positivity_final/typeA.cpp0000600000175000017500000002307010011171251017407 0ustar duclouxducloux00000000000000/* This is typeA.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "typeA.h" /***************************************************************************** Chapter I -- The TypeACoxGroup class This class provides some extra features for groups of type A (i.e., symmetric groups.) In fact, we are especially interested in i/o in permutation form. This is also a little test of the flexibility of the Coxeter group hierarchy. ******************************************************************************/ namespace typeA { TypeACoxGroup::TypeACoxGroup(const Rank& l):FiniteCoxGroup(Type("A"),l) /* Constructor for the type A Coxeter groups. */ { delete d_interface; d_typeAInterface = new TypeAInterface(l); d_interface = d_typeAInterface; } TypeACoxGroup::~TypeACoxGroup() {} bool TypeACoxGroup::parseGroupElement(ParseInterface& P) const { Ulong r = P.offset; if (parseContextNumber(P)) { // the next token is a ContextNumber if (ERRNO) // parse error return true; else goto modify; } // if we get to this point, we have to read a CoxWord if (hasPermutationInput()) { typeAInterface().parsePermutation(P); } else { interface().parseCoxWord(P,mintable()); } if (ERRNO) { // no CoxWord could be parsed if (P.offset == r) { // nothing was parsed ERRNO = 0; return false; } else // parse error return true; } modify: // if we get to this point, a group element was successfully read while (parseModifier(P)) { if (ERRNO) return true; } // flush the current group element prod(P.a[P.nestlevel],P.c); P.c.reset(); if (P.offset == r) // nothing was read; c is unchanged return false; else return true; } }; /**************************************************************************** Chapter II --- Derived classes The only derived class for which something special has to be done is the TypeAMedRankCoxGroup class, which fills in the minroot table. *****************************************************************************/ namespace typeA { TypeAMedRankCoxGroup::TypeAMedRankCoxGroup(const Rank& l):TypeACoxGroup(l) { mintable().fill(graph()); /* an error is set here in case of failure */ return; } TypeAMedRankCoxGroup::~TypeAMedRankCoxGroup() {} bool TypeASmallCoxGroup::parseDenseArray(ParseInterface& P) const /* Tries to parse a DenseArray from P. This is a '#' character, followed by an integer which has to lie in the range [0,N[, where N is the size of the group. */ { const Interface& I = interface(); Token tok = 0; Ulong p = I.getToken(P,tok); if (p == 0) return false; if (!isDenseArray(tok)) return false; // if we get to this point, we must read a valid integer P.offset += p; CoxNbr x = interface::readCoxNbr(P,d_order); if (x == undef_coxnbr) { //error P.offset -= p; Error(DENSEARRAY_OVERFLOW,d_order); ERRNO = PARSE_ERROR; } else { // x is valid CoxWord g(0); prodD(g,x); CoxGroup::prod(P.c,g); } return true; } bool TypeASmallCoxGroup::parseGroupElement(ParseInterface& P) const /* This is the parseGroupElement function for the SmallCoxGroup type. In this class, we have one additional representation of elements, viz. the densearray representation. This means that an element that would be represented by the array [x_1, ... ,x_n] is represented by the number w = x_1+x_2*a_1+ ... +x_n*a_{n-1}, where a_j is the size of the j'th subgroup in the filtration. This will give a bijective correspondence between group elements and numbers in the range [0,N-1], where N is the size of the group. */ { Ulong r = P.offset; if (parseContextNumber(P)) { // next token is a context number if (ERRNO) // parse error return true; else goto modify; } if (parseDenseArray(P)) { // next token is a dense array if (ERRNO) // parse error return true; else goto modify; } // if we get to this point, we have to read a CoxWord if (hasPermutationInput()) { typeAInterface().parsePermutation(P); } else { interface().parseCoxWord(P,mintable()); } if (ERRNO) { // no CoxWord could be parsed if (P.offset == r) { // nothing was parsed ERRNO = 0; return false; } else // parse error return true; } modify: // if we get to this point, a group element was successfully read while (parseModifier(P)) { if (ERRNO) return true; } // flush the current group element prod(P.a[P.nestlevel],P.c); P.c.reset(); if (P.offset == r) // nothing was read; c is unchanged return false; else return true; } int TypeASmallCoxGroup::prodD(CoxWord& g, const DenseArray& d_x) const /* Does the multiplication of g by x, by recovering the normal pieces of x. returns the length increase. */ { const Transducer& T = d_transducer[0]; DenseArray x = d_x; int l = 0; for (Ulong j = 0; j < rank(); ++j) { const FiltrationTerm& X = T.transducer(rank()-1-j)[0]; ParNbr c = x%X.size(); l += CoxGroup::prod(g,X.np(c)); x /= X.size(); } return l; } }; /**************************************************************************** Chapter III --- The TypeAInterface class Special interface for type A. It has the capacity of outputting elements in permutation form. For simplicity, we catch permutations as Coxeter elements in a group one rank bigger. *****************************************************************************/ namespace typeA { TypeAInterface::TypeAInterface(const Rank& l):Interface(Type("A"),l) { d_pInterface = new Interface(Type("A"),l+1); GroupEltInterface GI(l+1,HexadecimalFromZero()); d_pInterface->setIn(GI); d_pInterface->setOut(GI); }; TypeAInterface::~TypeAInterface() { delete d_pInterface; }; String& TypeAInterface::append(String& str, const CoxWord& g) const /* Special append function for type A. If hasPermutationOutput is true, it outputs elements in permutation form. */ { if (hasPermutationOutput()) { // print out as permutation CoxWord a(0); a.setLength(d_pInterface->rank()); coxWordToPermutation(a,g); return d_pInterface->append(str,a); } else { return interface::append(str,g,*d_out); } } bool TypeAInterface::parsePermutation(ParseInterface& P) const /* Parses a permutation. For us, a permutation should be represented as a Coxeter element in a group of rank one bigger. */ { Ulong r = P.offset; d_pInterface->readCoxElt(P); if (ERRNO == NOT_COXELT) { Error(NOT_PERMUTATION); ERRNO = PARSE_ERROR; return true; } if (P.offset > r) permutationToCoxWord(P.c,P.c); return true; } void TypeAInterface::print(FILE* file, const CoxWord& g) const /* Special print function for type A. If hasPermutationOutput is true, it outputs elements in permutation form. */ { if (hasPermutationOutput()) { // print out as permutation CoxWord a(0); a.setLength(d_pInterface->rank()); coxWordToPermutation(a,g); d_pInterface->print(file,a); } else { interface::print(file,g,*d_out); } return; } void TypeAInterface::setIn(const GroupEltInterface& i) /* Resets d_in to i, and clears hasPermutationInput. */ { delete d_in; d_in = new GroupEltInterface(i); readSymbols(); setAutomaton(); setPermutationInput(false); return; } void TypeAInterface::setOut(const GroupEltInterface& i) /* Resets d_out to i, and clears hasPermutationOutput. */ { delete d_out; d_out = new GroupEltInterface(i); setPermutationOutput(false); return; } }; /***************************************************************************** Chapter IV -- Functions declared in typeA.h This section defines the following functions declared in typeA.h : - permutationToCoxWord(g,a) : puts in g a reduced expression of the permutation a; - coxWordToPermutation(a,g) : the other way around; ******************************************************************************/ namespace typeA { void coxWordToPermutation(CoxWord& a, const CoxWord& g) /* Puts in a the permutation of the numbers {0,...,l} whose reduced expression is contained in g. It should be safe to even when a = g (i.e., we make a copy of g before overwriting a). NOTE : it is assumed that a.length() = rank+1 is alreaady set to the correct size. */ { CoxWord h(g); for (Ulong j = 0; j < a.length(); ++j) a[j] = j+1; for (Ulong j = 0; j < h.length(); ++j) { Generator s = h[j]-1; // interchange a[s] and a[s+1] Generator t = a[s+1]; a[s+1] = a[s]; a[s] = t; } return; } void permutationToCoxWord(CoxWord& g, const CoxWord& a) /* Puts in g the standard normal form of a, which is assumed to hold a permutation of the integers {0,...,l}. It should be safe even when a = g (i.e., we make a copy of a before overwriting g). The algorithm is as follows : look at the position of l in a, say a[j] = l. Then we rotate counterclockwise the entries in a from j to l, so that now a[l] = l, and the other a[j] are < l; and finally put l-j into a[l]. This will be the length of the last "slice" s_l...s_{j+1} in the normal form. Then iterate. */ { CoxWord b(a); Length c = 0; for (Rank l = b.length()-1; l; --l) { Rank j = 0; for (; b[l-j] != l+1; ++j) ; for (Rank i = l-j; i < l; ++i) b[i] = b[i+1]; b[l] = j; c += j; } g.setLength(c); g[c] = '\0'; c = 0; for (Ulong j = 1; j < b.length(); ++j) { for (Ulong i = 0; i < b[j]; ++i) g[c+i] = j-i; c += b[j]; } return; } }; positivity_final/typeA.h0000600000175000017500000001670210011171251017060 0ustar duclouxducloux00000000000000/* This is typeA.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /**************************************************************************** This module declares some special features for groups of type A. Currently this is just at the level of i/o, being able to input and output elements as permutations. ****************************************************************************/ #ifndef TYPEA_H /* guard against multiple inclusions */ #define TYPEA_H #include "globals.h" #include "fcoxgroup.h" namespace typeA { using namespace globals; using namespace fcoxgroup; }; /******** type declarations *************************************************/ namespace typeA { class TypeAInterface; class TypeACoxGroup; class TypeABigRankCoxGroup; class GeneralTypeABRCoxGroup; class TypeAMedRankCoxGroup; class GeneralTypeAMRCoxGroup; class TypeASmallRankCoxGroup; class GeneralTypeASRCoxGroup; class TypeASmallCoxGroup; class GeneralTypeASCoxGroup; }; /******** function declarations *********************************************/ namespace typeA { void coxWordToPermutation(CoxWord& a, const CoxWord& g); void permutationToCoxWord(CoxWord& g, const CoxWord& a); }; /******** type definitions **************************************************/ namespace typeA { class TypeACoxGroup:public FiniteCoxGroup { TypeAInterface* d_typeAInterface; public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TypeACoxGroup));} TypeACoxGroup(const Rank& l); virtual ~TypeACoxGroup(); // accessors void coxWordToPermutation(CoxWord& a, const CoxWord& g) const; bool hasPermutationInput() const; /* inlined */ bool hasPermutationOutput() const; /* inlined */ void permutationToCoxWord(CoxWord& g, const CoxWord& a) const; const TypeAInterface& typeAInterface() const; /* inlined */ // manipulators void setPermutationInput(bool b); /* inlined */ void setPermutationOutput(bool b); /* inlined */ TypeAInterface& typeAInterface(); /* inlined */ // i/o virtual bool parseGroupElement(ParseInterface& P) const; }; class TypeABigRankCoxGroup:public TypeACoxGroup { public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TypeABigRankCoxGroup));} TypeABigRankCoxGroup(const Rank& l):TypeACoxGroup(l) {}; virtual ~TypeABigRankCoxGroup() {}; }; class GeneralTypeABRCoxGroup:public TypeABigRankCoxGroup { // leaf class public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralTypeABRCoxGroup));} GeneralTypeABRCoxGroup(const Rank& l):TypeABigRankCoxGroup(l) {}; ~GeneralTypeABRCoxGroup() {}; }; class TypeAMedRankCoxGroup:public TypeACoxGroup { public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TypeAMedRankCoxGroup));} TypeAMedRankCoxGroup(const Rank& l); virtual ~TypeAMedRankCoxGroup(); }; class GeneralTypeAMRCoxGroup:public TypeAMedRankCoxGroup { // leaf class public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralTypeAMRCoxGroup));} GeneralTypeAMRCoxGroup(const Rank& l):TypeAMedRankCoxGroup(l) {}; ~GeneralTypeAMRCoxGroup() {}; }; class TypeASmallRankCoxGroup:public TypeAMedRankCoxGroup { public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TypeASmallRankCoxGroup));} TypeASmallRankCoxGroup(const Rank& l):TypeAMedRankCoxGroup(l) {}; virtual ~TypeASmallRankCoxGroup() {}; }; class GeneralTypeASRCoxGroup:public TypeASmallRankCoxGroup { // leaf class public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralTypeASRCoxGroup));} GeneralTypeASRCoxGroup(const Rank& l):TypeASmallRankCoxGroup(l) {}; ~GeneralTypeASRCoxGroup() {}; }; class TypeASmallCoxGroup: public TypeASmallRankCoxGroup { public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TypeASmallCoxGroup));} TypeASmallCoxGroup(const Rank& l):TypeASmallRankCoxGroup(l) {}; virtual ~TypeASmallCoxGroup() {}; // accessors int prodD(CoxWord& g, const DenseArray& d_x) const; // i/o bool parseDenseArray(ParseInterface& P) const; virtual bool parseGroupElement(ParseInterface& P) const; }; class GeneralTypeASCoxGroup:public TypeASmallCoxGroup { // leaf class public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(GeneralTypeASCoxGroup));} GeneralTypeASCoxGroup(const Rank& l):TypeASmallCoxGroup(l) {}; ~GeneralTypeASCoxGroup() {}; }; class TypeAInterface:public Interface { Interface* d_pInterface; bool d_hasPermutationInput; bool d_hasPermutationOutput; public: // constructors and destructors void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(TypeAInterface));} TypeAInterface(const Rank& l); virtual ~TypeAInterface(); // accessors bool hasPermutationInput() const; /* inlined */ bool hasPermutationOutput() const; /* inlined */ bool parsePermutation(ParseInterface& P) const; // manipulators virtual void setIn(const GroupEltInterface& i); virtual void setOut(const GroupEltInterface& i); void setPermutationInput(bool b); /* inlined */ void setPermutationOutput(bool b); /* inlined */ // i/o virtual String& append(String& str, const CoxWord& g) const; virtual void print(FILE* file, const CoxWord& g) const; }; }; /******** inline definitions ************************************************/ namespace typeA { inline bool TypeAInterface::hasPermutationInput() const {return d_hasPermutationInput;} inline bool TypeAInterface::hasPermutationOutput() const {return d_hasPermutationOutput;} inline void TypeAInterface::setPermutationInput(bool b) {d_hasPermutationInput = b;} inline void TypeAInterface::setPermutationOutput(bool b) {d_hasPermutationOutput = b;} inline bool TypeACoxGroup::hasPermutationInput() const {return d_typeAInterface->hasPermutationInput();} inline bool TypeACoxGroup::hasPermutationOutput() const {return d_typeAInterface->hasPermutationOutput();} inline void TypeACoxGroup::setPermutationInput(bool b) {typeAInterface().setPermutationInput(b);} inline void TypeACoxGroup::setPermutationOutput(bool b) {typeAInterface().setPermutationOutput(b);} inline const TypeAInterface& TypeACoxGroup::typeAInterface() const {return *d_typeAInterface;} inline TypeAInterface& TypeACoxGroup::typeAInterface() {return *d_typeAInterface;} }; #endif positivity_final/uneqkl.cpp0000600000175000017500000012574610011171251017641 0ustar duclouxducloux00000000000000/* This is uneqkl.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "uneqkl.h" #include "interactive.h" namespace uneqkl { using namespace interactive; } namespace { using namespace uneqkl; void muSubtraction(KLPol& p, const MuPol& mp, const KLPol& q, const Ulong& d, const long& m); void positivePart(KLPol& p, const KLPol& q, const Ulong& d, const long& m); const MuPol* writeMu(BinaryTree& t, const KLPol& p); }; namespace uneqkl { struct KLContext::KLHelper { /* data */ KLContext* d_kl; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLHelper));} KLHelper(KLContext* kl):d_kl(kl) {}; ~KLHelper() {}; /* member functions */ void allocExtrRow(const CoxNbr& y) {klsupport().allocExtrRow(y);} void allocKLRow(const CoxNbr& y); void allocMuRow(const Generator& s, const CoxNbr& y); void allocMuRow(MuRow& row, const Generator& s, const CoxNbr& y); bool checkKLRow(const CoxNbr& y); bool checkMuRow(const Generator& s, const CoxNbr& y); void ensureKLRow(const CoxNbr& y); const ExtrRow& extrList(const CoxNbr& y) {return klsupport().extrList(y);} void fillKLRow(const CoxNbr& y, const Generator& s = undef_generator); void fillMuRow(const Generator& s, const CoxNbr& y); const KLPol* fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& s = undef_generator); const MuPol* fillMu(const Generator& s, const CoxNbr& x, const CoxNbr& y); const KLPol& find(const KLPol& p) {return d_kl->d_klTree.find(p)[0];} Ulong genL(const Generator& s) {return d_kl->genL(s);} void initWorkspace(const CoxNbr& y, List& pol, const Generator& s); CoxNbr inverse(const CoxNbr& y) {return klsupport().inverse(y);} void inverseMin(CoxNbr& y, Generator& s); bool isExtrAllocated(const CoxNbr& y) {return klsupport().isExtrAllocated(y);} bool isKLAllocated(const CoxNbr& y) {return d_kl->isKLAllocated(y);} KLRow& klList(const CoxNbr& y) {return d_kl->d_klList[y][0];} const KLPol& klPol(const CoxNbr& x, const CoxNbr& y) {return d_kl->klPol(x,y);} KLSupport& klsupport() {return d_kl->d_klsupport[0];} BinaryTree& klTree() {return d_kl->d_klTree;} Generator last(const CoxNbr& x) {return klsupport().last(x);} Ulong length(const CoxNbr& x) {return d_kl->length(x);} const MuPol& mu(const Generator& s, const CoxNbr& x, const CoxNbr& y) {return d_kl->mu(s,x,y);} void muCorrection(List& pol, const Generator& s, const CoxNbr& y); void muCorrection(const CoxNbr& x, const Generator& s, const CoxNbr& y, List& pol, const Ulong& a); MuRow& muList(const Generator& s, const CoxNbr& y) {return d_kl->d_muTable[s][0][y][0];} MuTable& muTable(const Generator& s) {return d_kl->d_muTable[s][0];} BinaryTree& muTree() {return d_kl->d_muTree;} void prepareRowComputation(const CoxNbr& y, const Generator& s); Rank rank() {return d_kl->rank();} const SchubertContext& schubert() {return klsupport().schubert();} void secondTerm(const CoxNbr& y, List& pol, const Generator& s); Ulong size() {return d_kl->size();} KLStatus& status() {return *d_kl->d_status;} void writeMuRow(const MuRow& row, const Generator& s, const CoxNbr& y); void writeKLRow(const CoxNbr& y, List& pol); }; }; /* This module contains code for the computation of kl polynomials with unequal parameters. Even though the general setup is similar to that for the ordinary kl polynomials, there are several important technical differences : - the polynomials are now Laurent polynomials in the indeterminate q; morevoer they need not have positive coefficients. - the mu-coefficients are no longer integers, but Laurent polynomials themselves; there is one family of mu-coefficients for each conjugacy class of generators (equivalently, for each connected component of the Coxeter graph, after suppression of the links with an even or infinite label.) The reference for this construction are Lusztig's course notes. The basic datum is for each generator s an element v_s in Z[q^{1/2},q^{-1/2}] , a positive integral power of v = q^{1/2}, constant under conjugacy in W. Then the Hecke algebra is defined by generators t_s, s in S, and relations : (t_s-v_s)(t_s+v_s^{-1}) = 0, plus the braid relations (these t_s are related to the "ordinary" T_s by t_s = v_s^{-1}T_s). This implies that t_s.t_w is t_{sw} when sw > w, and t_{sw} - a_s.t_w otherwise, where a_s = v_s^{-1}-v_s. Also we have t_s^{-1} = t_s + a_s for each s in S. Then there is an A-antilinear ring involution on H defined as usual by t_x^{-1} = t_{x^{-1}}^{-1}. This defines a formal R-function on the group W, hence a Kazhdan-Lusztig basis c_x, x in W. As usual, c_x is the unique self-adjoint element in H such that c_x = t_x mod H_{<0}, where H_{<0} is the direct sum of the v^{-1}Z[v^{-1}]t_x. It turns out that c_y is of the form : c_y = t_y + sum_{x e in W, and let s in S such that sy < y. Then the element c_sc_{sy} is known; it is equal to : (t_s + v_s^{-1})(t_{ys} + sum_{x x, sx not comparable to sy = v_s^{-1}.p(x,sy)+p(sx,sy)-sum_{x<=z y. It is not clear to me to what extent the mu^s depend only on the conjugacy class of s. For one thing, the domain is not the same; but on the intersection of domains ? Anyway, for now I'll make one table for each s. */ /* This part of the program is of a more exploratory nature than the rest. */ /***************************************************************************** Chapter I -- The KLContext class Just like the ordinary k-l polynomials, the KLContext class holds the polynomial tables and the mu-lists, and provides the functions to access and output them. Since we restrict ourselves to positive length functions, the polynomials can be reduced to extremal pairs; hence the polynomial tables are synchronized with the extrList tables in the klsupport part (which is shared among all k-l tables.) The following functions are provided : - constructors and destructors : - KLContext(KLSupport* kls); - ~KLContext(); - accessors not already inlined : - manipulators : - applyInverse(const CoxNbr& x) : auxiliary to permute; - fillKL() : fills the full k-l table; - fillMu() : fills the full mu-tables; - fillMu(s) : fills the full mu-table for generator s; - klPol(cont CoxNbr& x, const CoxNbr& y) : returns P_{x,y}; - row(Permutation& a, const CoxNbr& y) : fills the row for y and returns an appropriate sort of it in a; - permute(const Permutation&) : applies a permutation to the context; - revertSize(const Ulong&) : reverts the size to a previous value; - setSize(const Ulong&) : sets the size to a larger value; *****************************************************************************/ namespace uneqkl { KLContext::KLContext(KLSupport* kls, const CoxGraph& G, const Interface& I) :d_klsupport(kls),d_klList(0),d_muTable(0),d_L(0),d_length(0) /* This constructor gets the lengths interactively from the user. This makes it possible that an error is set during the construction. Fortunately we can check this before any memory is gotten from the heap, so that automatic destruction of the components on exit will be satisfactory in that case. */ { d_L.setSize(2*rank()); getLength(d_L,G,I); if (ERRNO) { /* error code is ABORT */ goto end; } d_status = new KLStatus; d_help = new KLHelper(this); d_klList.setSize(kls->size()); d_klList[0] = new KLRow(1); d_klList[0]->setSize(1); (*d_klList[0])[0] = d_klTree.find(one()); d_status->klrows++; d_status->klnodes++; d_status->klcomputed++; d_muTable.setSize(rank()); for (Generator s = 0; s < d_muTable.size(); ++s) { d_muTable[s] = new MuTable(kls->size()); MuTable& t = *d_muTable[s]; t.setSizeValue(kls->size()); t[0] = new MuRow(0); } d_length.setSize(kls->size()); for (CoxNbr x = 1; x < d_length.size(); ++x) { Generator s = last(x); CoxNbr xs = schubert().shift(x,s); d_length[x] = d_length[xs] + d_L[s]; } end: ; } KLContext::~KLContext() { for (Ulong j = 0; j < d_klList.size(); ++j) { delete d_klList[j]; } for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; for (Ulong j = 0; j < t.size(); ++j) { delete t[j]; } delete d_muTable[s]; } } /******** accessors **********************************************************/ /******** manipulators *******************************************************/ void KLContext::applyInverse(const CoxNbr& x) /* Exchanges rows for x and x_inverse in klList. It is assumed that the row for x_inverse is allocated. */ { CoxNbr xi = inverse(x); d_klList[x] = d_klList[xi]; d_klList[xi] = 0; return; } void KLContext::fillKL() /* Fills the full k-l table for the current context. */ { for (CoxNbr y = 0; y < size(); ++y) { if (inverse(y) < y) continue; if (!d_help->checkKLRow(y)) d_help->fillKLRow(y); } return; } void KLContext::fillMu() /* Fills the full mu tables for the current context. */ { for (Generator s = 0; s < rank(); ++s) fillMu(s); return; } void KLContext::fillMu(const Generator& s) /* Fills the full mu table for generator s for the current context. */ { for (CoxNbr y = 0; y < size(); ++y) { if (schubert().isDescent(y,s)) continue; if (!d_help->checkMuRow(s,y)) d_help->fillMuRow(s,y); } return; } const KLPol& KLContext::klPol(const CoxNbr& d_x, const CoxNbr& d_y) /* This function returns the Kazhdan-Lusztig polynomial P_{x,y}. It is assumed that the condition x <= y has already been checked, and that x and y are valid context numbers. */ { const SchubertContext& p = schubert(); CoxNbr x = d_x; CoxNbr y = d_y; /* put x in extremal position w.r.t. y */ x = p.maximize(x,p.descent(y)); /* go to inverses if necessary */ if (inverse(y) < y) { y = inverse(y); x = inverse(x); } /* check if extrList[y] is allocated */ if (!isKLAllocated(y)) { d_help->allocKLRow(y); if (ERRNO) return errorPol(); } /* find x in extrList[y] */ Ulong m = find(extrList(y),x); const KLPol* pol = (*d_klList[y])[m]; if (pol == 0) { /* we have to compute the polynomial */ pol = d_help->fillKLPol(x,y); if (ERRNO) return errorPol(); } return *pol; } const MuPol& KLContext::mu(const Generator& s, const CoxNbr& x, const CoxNbr& y) /* This function returns mu^s_{x,y}, filling it in if necessary. It is assumed that the conditions x < y, ys > y, xs < x have already been checked. */ { if (!isMuAllocated(s,y)) d_help->allocMuRow(s,y); const MuRow& mu_row = muList(s,y); /* find x in row */ MuData mx(x,0); Ulong m = find(mu_row,mx); if (m == not_found) return zero(); const MuPol* mp = mu_row[m].pol; if (mp == 0) { /* mu-polynomial must be computed */ mp = d_help->fillMu(s,x,y); if (ERRNO) return errorMuPol(); } return *mp; } void KLContext::permute(const Permutation& a) /* Applies the permutation a to the context. See the permute function of KLSupport for a detailed explanation. */ { /* permute values */ for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; for (CoxNbr y = 0; y < size(); ++y) { if (!isMuAllocated(s,y)) continue; MuRow& row = *t[y]; for (Ulong j = 0; j < row.size(); ++j) row[j].x = a[row[j].x]; row.sort(); } } /* permute ranges */ BitMap b(a.size()); for (CoxNbr x = 0; x < size(); ++x) { if (b.getBit(x)) continue; if (a[x] == x) { b.setBit(x); continue; } List mu_buf(0); mu_buf.setSize(d_muTable.size()); for (CoxNbr y = a[x]; y != x; y = a[y]) { /* back up values for y */ KLRow* kl_buf = d_klList[y]; for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; mu_buf[s] = t[y]; } Length length_buf = d_length[y]; /* put values for x in y */ d_klList[y] = d_klList[x]; for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; t[y] = t[x]; } d_length[y] = d_length[x]; /* store backup values in x */ d_klList[x] = kl_buf; for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; t[x] = mu_buf[s]; } d_length[x] = length_buf; /* set bit*/ b.setBit(y); } b.setBit(x); } return; } void KLContext::revertSize(const Ulong& n) /* Reverts the sizes of the lists to size n. This is meant to be used only immediately after a failing context extension, to preserve the consistency of the various list sizes. In particular, it will fail miserably if a premutation has taken place in-between. */ { d_klList.setSize(n); for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; t.setSize(n); } d_length.setSize(n); return; } void KLContext::row(HeckeElt& h, const CoxNbr& y) /* This function makes sure that the row corresponding to y in the k-l table is entirely filled, and returns in h the corresponding data, sorted in the order of increasing context numbers. */ { if (!d_help->checkKLRow(y)) { d_klsupport->allocRowComputation(y); if (ERRNO) goto error_exit; d_help->fillKLRow(y); if (ERRNO) goto error_exit; } { if (y <= inverse(y)) { const ExtrRow& e = extrList(y); h.setSize(e.size()); const KLRow& klr = klList(y); for (Ulong j = 0; j < e.size(); ++j) { h[j].setData(e[j],klr[j]); } } else { /* go over to inverses */ CoxNbr yi = inverse(y); const ExtrRow& e = extrList(yi); h.setSize(e.size()); const KLRow& klr = klList(yi); for (Ulong j = 0; j < e.size(); ++j) { h[j].setData(inverse(e[j]),klr[j]); } h.sort(); /* make sure list is ordered */ } } return; error_exit: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::setSize(const Ulong& n) /* This function adjusts the size of the context to a context of size n. */ { CoxNbr prev_size = size(); CATCH_MEMORY_OVERFLOW = true; d_klList.setSize(n); if (ERRNO) goto revert; for (Generator s = 0; s < d_muTable.size(); ++s) { MuTable& t = *d_muTable[s]; t.setSize(n); if (ERRNO) goto revert; } d_length.setSize(n); if (ERRNO) goto revert; CATCH_MEMORY_OVERFLOW = false; /* fill in new Lengths */ for (CoxNbr x = prev_size; x < n; ++x) { Generator s = last(x); CoxNbr xs = schubert().shift(x,s); d_length[x] = d_length[xs] + genL(s); } return; revert: CATCH_MEMORY_OVERFLOW = false; revertSize(prev_size); return; } }; /***************************************************************************** Chapter II -- The KLHelper class. The purpose of the KLHelper class is to hide from the public eye a number of helper functions, used in the construction and maintenance of the k-l context. This unclutters kl.h quite a bit. The following functions are defined : - allocKLRow(y) : allocates one row in the k-l table; - allocMuRow(row,s,y) : allocates row to a full mu-row for y and s; - allocMuRow(s,y) : allocates the row for y in muTable(s); - checkKLRow(y) : checks if the row for y (or inverse(y)) if appropriate) in the k-l table has been filled; - fillKLRow(y) : fills the row for y or inverse(y); - fillKLPol(x,y) : fills in P_{x,y}; - initWorkspace(y,pol,s) : auxiliary to fillKLRow; - inverseMin(y,s) : reflects y and s if inverse(y) < y; - muCorrection(pol,s,y) : auxiliary to fillKLRow; - prepareRowComputation(y,s) : auxiliary to fillKLRow; - secondTerm(y,pol,s) : ausiliary to fillKLRow; - writeKLRow(y,pol) : auxiliary to fillKLRow; *****************************************************************************/ namespace uneqkl { void KLContext::KLHelper::allocKLRow(const CoxNbr& y) /* Allocates one previously unallocated row in the k-l table. It is assumed that y <= inverse(y). Allocates the corresponding extremal row if necessary. Forwards a memory error in case of failure if CATCH_MEMORY_ERROR is set. */ { if (!isExtrAllocated(y)) allocExtrRow(y); Ulong n = extrList(y).size(); d_kl->d_klList[y] = new KLRow(n); if (ERRNO) return; klList(y).setSizeValue(n); status().klnodes += n; status().klrows++; return; } void KLContext::KLHelper::allocMuRow(const Generator& s, const CoxNbr& y) /* Allocates one previously unallocated row in muTable(s). For unequal parameters, we don't try to be particularly smart. The row for y contains one entry for each x < y s.t. xs < x (it is already implicit that ys > y, or the row would not even be allocated.) */ { MuTable& t = muTable(s); t[y] = new MuRow(0); allocMuRow(muList(s,y),s,y); d_kl->d_status->munodes += muList(s,y).size(); d_kl->d_status->murows++; return; } void KLContext::KLHelper::allocMuRow(MuRow& row, const Generator& s, const CoxNbr& y) /* Allocates row to the full mu-row for y and s. For unequal parameters, we don't try to be particularly smart. The row for y contains one entry for each x < y s.t. xs < x (it is already implicit that ys > y, or the row would not even be allocated.) */ { BitMap b(0); schubert().extractClosure(b,y); b &= schubert().downset(s); row.setSize(0); BitMap::Iterator b_end = b.end(); for (BitMap::Iterator k = b.begin(); k != b_end; ++k) { MuData md(*k,0); row.append(md); } return; } bool KLContext::KLHelper::checkKLRow(const CoxNbr& d_y) /* Checks if the row corresponding to y in the k-l table has been completely filled. Checks for inverse if y_inverse < y. */ { CoxNbr y = d_y; if (inverse(y) < y) y = inverse(y); if (!isKLAllocated(y)) return false; const KLRow& kl_row = klList(y); for (Ulong j = 0; j < kl_row.size(); ++j) { if (kl_row[j] == 0) return false; } return true; } bool KLContext::KLHelper::checkMuRow(const Generator& s, const CoxNbr& y) /* Checks if the row corresponding to y in muTable[s] has been completely filled. Checks for inverse(y) if it is smaller than y. */ { const MuTable& t = muTable(s); if (t[y] == 0) return false; const MuRow& mr = *t[y]; for (Ulong j = 0; j < mr.size(); ++j) { if (mr[j].pol == 0) return false; } return true; } void KLContext::KLHelper::ensureKLRow(const CoxNbr& y) /* Makes sure that the k-l row for y is available. */ { if (!checkKLRow(y)) { klsupport().allocRowComputation(y); if (ERRNO) goto abort; fillKLRow(y); if (ERRNO) goto abort; } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } const KLPol* KLContext::KLHelper::fillKLPol(const CoxNbr& x, const CoxNbr& y, const Generator& d_s) /* This function fills in a single polynomial in the k-l table (as opposed to fillKLRow, which fills a whole row.) It isn't particularly optimized for speed; it is not a good idea to fill large parts of the table by repeated calls to fillKLPol. It is assumed that x <= y in the Bruhat order, y <= inverse(y), x extremal w.r.t. y, and that the row for y in the k-l table is allocated. */ { static List pol(0); /* workspace stack */ const SchubertContext& p = schubert(); Generator s = d_s; /* If d_s is undef_coxnbr, we compute the polynomial using descent by last term in normal form */ if (s == undef_generator) s = last(y); CoxNbr ys = p.shift(y,s); CoxNbr xs = p.shift(x,s); /* check if x is comparable to ys */ if (!p.inOrder(x,ys)) { /* return the answer immediately */ status().klcomputed++; Ulong m = list::find(extrList(y),x); klList(y)[m] = &klPol(xs,ys); return klList(y)[m]; } /* get workspace */ CATCH_MEMORY_OVERFLOW = true; Ulong a = pol.size(); pol.setSize(a+1); /* initialize the workspace to P_{xs,ys} */ const KLPol& p_xsys = klPol(xs,ys); if (ERRNO) goto abort; pol[a] = p_xsys; /* add q.P_{x,ys} */ { const KLPol& p_xys = klPol(x,ys); if (ERRNO) goto abort; pol[a].add(p_xys,genL(s)); if (ERRNO) goto abort; } /* subtract correction terms */ muCorrection(x,s,y,pol,a); if (ERRNO) goto abort; /* find address of polynomial */ { const KLPol& p_xy = find(pol[a]); if (ERRNO) goto abort; Ulong m = list::find(extrList(y),x); klList(y)[m] = &p_xy; /* return workspace and exit */ CATCH_MEMORY_OVERFLOW = false; pol.setSize(a); status().klcomputed++; return &p_xy; } abort: /* an error occurred */ CATCH_MEMORY_OVERFLOW = false; if (ERRNO != MEMORY_WARNING) ERRNO = KL_FAIL; pol.setSize(a); return 0; } void KLContext::KLHelper::fillKLRow(const CoxNbr& d_y, const Generator& d_s) /* This function fills one row in the k-l table entirely. This can be done rather more efficiently than computing each polynomial individually : in particular, most of the closure computations can be "factored" for the whole row at a time. It is assumed that checkKLRow(y) returns false. The row which is actually filled is the one for the smaller of (y,inverse(y)). */ { static List pol(0); CoxNbr y = d_y; if (inverse(y) < y) /* fill in the row for inverse(y) */ y = inverse(y); if (!isKLAllocated(y)) allocKLRow(y); /* make sure the necessary terms are available */ Generator s = d_s; if (s == undef_generator) s = last(y); prepareRowComputation(y,s); if (ERRNO) goto abort; /* prepare workspace; pol holds the row of polynomials; initialize workspace with P_{xs,ys} */ initWorkspace(y,pol,s); /* add q.P_{x,ys} when appropriate */ secondTerm(y,pol,s); if (ERRNO) goto abort; /* subtract correcting terms */ muCorrection(pol,s,y); if (ERRNO) goto abort; /* copy results to row */ writeKLRow(y,pol); if (ERRNO) goto abort; return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } const MuPol* KLContext::KLHelper::fillMu(const Generator& s, const CoxNbr& x, const CoxNbr& y) /* Fills in the mu-polynomial for s,x,y. It is assumed that x < y, sy > y, sx < x. Recall that the mu-polynomial is the unique symmetric Laurent polynomial whose positive part is the same as that of : q^{L(s)/2}p(x,y) - \sum_{x pos_mu(0); // workspace stack MuRow& mu_row = muList(s,y); /* initialize a with the value u^(L(x)-L(y)+L(s))P_{x,y}(u^2) */ const KLPol& pol = klPol(x,y); if (ERRNO) { Error(MU_FAIL,x,y); ERRNO = ERROR_WARNING; return 0; } Ulong a = pos_mu.size(); pos_mu.setSize(a+1); positivePart(pos_mu[a],pol,2,length(x)-length(y)+genL(s)); MuData mx(x,0); Ulong m = list::find(mu_row,mx); // search cannot fail /* subtract correcting terms */ const SchubertContext& p = schubert(); for (Ulong j = m+1; j < mu_row.size(); ++j) { CoxNbr z = mu_row[j].x; if (!p.inOrder(x,z)) continue; const KLPol& pol = klPol(x,z); if (ERRNO) { Error(MU_FAIL,x,y); ERRNO = ERROR_WARNING; return 0; } const MuPol& mq = d_kl->mu(s,z,y); if (!mq.isZero()) muSubtraction(pos_mu[a],mq,pol,2,length(x)-length(z)); if (ERRNO) { Error(MU_FAIL,x,y); ERRNO = ERROR_WARNING; return 0; } } /* write mu-polynomial and return value */ mu_row[m].pol = writeMu(muTree(),pos_mu[a]); pos_mu.setSize(a); return mu_row[m].pol; } void KLContext::KLHelper::fillMuRow(const Generator& s, const CoxNbr& y) /* This function fills one row in the mu-list for s. Recall that mu(x,y,s) is defined whenever x < y, sy > y, sx < x, and is a Laurent polynomial in u = q^{1/2}, symmetric w.r.t. q->q^-1. See fillMu for the formula defining mu. In order to avoid huge amounts of calls to the expensive inOrder, we proceed as in fillKLRow, computing the full row at a time. This appears to be a bit more difficult than for the kl-pols, because in the recursion we need mu's for the _same_ value of y, but as it turns out, when we need a mu(s,z,y), it is already fully computed, provided we proceed with the correcting terms in decreasing order. A number of k-l polynomials are needed in the process; it turns out that when one is needed, usually many will be for the same value of z; so again we fill the whole k-l row for z when a polynomial is needed. The problem with this is that it may trigger recursive calls to fillMuRow; hence we have to manage a workspace stack. An approach like prepareMuRow is not feasible here because we don't want to compute P_{x,z} if mu_{z,y} turns out to be zero, and we can know that only when we are already in the process of filling the row. */ { static List > posMu(0); static List muRow(0); /* the polynomial pos_mu(x) (really pos_mu[j], x = mu_list[j].x) holds the positive part of the mu-polynomial */ /* get workspace */ Ulong a = posMu.size(); posMu.setSize(a+1); muRow.setSize(a+1); allocMuRow(muRow[a],s,y); posMu[a].setSize(muRow[a].size()); CoxNbr x; /* initialize posMu[a](x) with the value u^(L(x)-L(y)+L(s))P_{x,y}(u^2) */ for (Ulong j = 0; j < muRow[a].size(); ++j) { ensureKLRow(y); x = muRow[a][j].x; const KLPol& pol = klPol(x,y); if (ERRNO) /* this cannot happen in typical usage */ goto abort; positivePart(posMu[a][j],pol,2,length(x)-length(y)+genL(s)); } /* we run through muRow[a] in decreasing order; for each z in the list, we subtract from the correction term corresponding to z from mu(x,y) for each x < z. */ for (Ulong j = muRow[a].size(); j;) { --j; /* write the mu-polynomial for z */ muRow[a][j].pol = writeMu(muTree(),posMu[a][j]); d_kl->d_status->mucomputed++; if (muRow[a][j].pol->isZero()) { d_kl->d_status->muzero++; continue; } /* subtract correcting terms */ CoxNbr z = muRow[a][j].x; ensureKLRow(z); if (ERRNO) goto abort; BitMap b(0); schubert().extractClosure(b,z); b &= schubert().downset(s); b.clearBit(z); BitMap::Iterator b_end = b.end(); Ulong i = 0; for (BitMap::Iterator k = b.begin(); k != b_end; ++k) { x = *k; while (muRow[a][i].x != x) ++i; const KLPol& pol = klPol(x,z); if (ERRNO) goto abort; muSubtraction(posMu[a][i],muRow[a][j].pol[0],pol,2, length(x)-length(z)); if (ERRNO) goto abort; ++i; } } writeMuRow(muRow[a],s,y); muRow.setSize(a); posMu.setSize(a); return; abort: Error(MU_FAIL,x,y); ERRNO = ERROR_WARNING; posMu.setSize(a); return; } void KLContext::KLHelper::initWorkspace(const CoxNbr& y, List& pol, const Generator& s) /* This function sets pol to a row of one polynomial for each x in klList(y), and initializes the corresponding pol[j] to klPol(xs,ys). It is assumed that prepareRowComputation has been called for y and s, so that the row for ys is available. */ { const SchubertContext& p = schubert(); const ExtrRow& e = extrList(y); pol.setSize(e.size()); if (ERRNO) goto abort; /* initialize with values P_{xs,ys} */ { CoxNbr ys = p.rshift(y,s); for (Ulong j = 0; j < e.size(); ++j) { CoxNbr xs = p.shift(e[j],s); pol[j] = klPol(xs,ys); /* no error can occur here */ } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::inverseMin(CoxNbr& y, Generator& s) /* Changes y to inverse(y), and s to the same generator on the other side, if inverse(y) < y. */ { if (inverse(y) < y) { y = inverse(y); if (s < rank()) s += rank(); else s -= rank(); } return; } void KLContext::KLHelper::muCorrection(List& pol, const Generator& s, const CoxNbr& y) /* This function carries out the "mu-correction" step in the computation of the row of K-L polynomials. It is assumed that pol holds one polynomial for each x <= y extremal w.r.t. y, that we are applying recursion w.r.t. s, and that the polynomials have been initialized to P_{xs,ys} +q^genL(s)P_{x,ys}. We have to subtract terms q^{(L(y)-L(z))/2}P_{x,z}mu(z,ys); from results of Lusztig it is known that these are actually polynomials in q as well. We minimize the number of calls to the Bruhat order functions by proceeding as follows : for each z in muList(s,ys), we extract the interval [e,z], extremalize w.r.t. y, and subtract the appropriate term from P_{x,y}. */ { const SchubertContext& p = schubert(); const ExtrRow& e = extrList(y); CoxNbr ys = p.rshift(y,s); const MuRow& mu_row = muList(s,ys); for (Ulong j = 0; j < mu_row.size(); ++j) { const MuPol& mu_pol = *mu_row[j].pol; if (mu_pol.isZero()) continue; CoxNbr z = mu_row[j].x; BitMap b(size()); p.extractClosure(b,z); maximize(p,b,p.descent(y)); Ulong i = 0; BitMap::Iterator b_end = b.end(); for (BitMap::Iterator k = b.begin(); k != b_end; ++k) { CoxNbr x = *k; while (e[i] < x) ++i; Ulong h = length(y)-length(z); pol[i].subtract(klPol(x,z),mu_pol,h); if (ERRNO) { Error(ERRNO,this,x,y); ERRNO = ERROR_WARNING; return; } } } return; } void KLContext::KLHelper::muCorrection(const CoxNbr& x, const Generator& s, const CoxNbr& y, List& pol, const Ulong& a) /* This function carries out the "mu-correction" step in the computation of a single K-L polynomial. Here pol is a stack, and a tells us at which level of the stack the owrk is done. It is assumed that pol[a] has been initialized to P_{xs,ys}+q^genL(s)P_{x,ys}. We have to subtract terms q^{(L(y)-L(z))/2}P_{x,z}mu(z,ys); from results of Lusztig it is known that these are actually polynomials in q as well. */ { const SchubertContext& p = schubert(); CoxNbr ys = p.rshift(y,s); if (!d_kl->isMuAllocated(s,ys)) { allocMuRow(s,ys); if (ERRNO) goto abort; } { const MuRow& mu_row = muList(s,ys); for (Ulong j = 0; j < mu_row.size(); ++j) { CoxNbr z = mu_row[j].x; if (!p.inOrder(x,z)) continue; const MuPol& mp = mu(s,z,ys); if (mp.isZero()) continue; Ulong h = length(y)-length(z); const KLPol& kl_pol = klPol(x,z); if (ERRNO) goto abort; pol[a].subtract(kl_pol,mp,h); if (ERRNO) goto abort; } } return; abort: Error(UEMU_FAIL,x,y); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::prepareRowComputation(const CoxNbr& y, const Generator& s) /* This function is an auxiliary to fillKLRow. It makes sure that the necessary terms for the filling of the row of y in the k-l table are available. This ensures that there will be no recursive calls to fillKLRow when the actual computation starts. At this point it is assumed that y <= inverse(y). */ { const SchubertContext& p = schubert(); CoxNbr ys = p.rshift(y,s); /* get the row for ys */ if (!checkKLRow(ys)) { fillKLRow(ys); if (ERRNO) goto abort; } { if (!checkMuRow(s,ys)) { fillMuRow(s,ys); if (ERRNO) goto abort; } const MuRow& mu_row = muList(s,ys); for (Ulong j = 0; j < mu_row.size(); ++j) { if (mu_row[j].pol->isZero()) continue; CoxNbr z = mu_row[j].x; if (!checkKLRow(z)) { klsupport().allocRowComputation(z); if (ERRNO) goto abort; fillKLRow(z); if (ERRNO) goto abort; } } } return; abort: Error(ERRNO); ERRNO = ERROR_WARNING; return; } void KLContext::KLHelper::secondTerm(const CoxNbr& y, List& pol, const Generator& s) /* This function adds the "second term", which is q^genL(s).P_{x,ys}, to the polynomials in pol. It is assumed that y <= inverse(y). In order to avoid calls to inOrder, we proceed as follows : we extract [e,ys], we extremalize it w.r.t. the descent set of y, and run through it to make the correction; this makes us run exactly through those x in the extremal list of y which are <= ys. */ { const SchubertContext& p = schubert(); BitMap b(size()); CoxNbr ys = p.rshift(y,s); p.extractClosure(b,ys); maximize(p,b,p.descent(y)); Ulong i = 0; BitMap::Iterator b_end = b.end(); const ExtrRow& e = extrList(y); for (BitMap::Iterator j = b.begin(); j != b_end; ++j) { CoxNbr x = *j; while(e[i] < x) ++i; pol[i].add(klPol(x,ys),genL(s)); if (ERRNO) { Error(ERRNO,this,x,y); ERRNO = ERROR_WARNING; return; } ++i; } return; } void KLContext::KLHelper::writeKLRow(const CoxNbr& y, List& pol) /* This function writes the polynomials from the list pol to klList(y); more precisely, it finds their adresses in klTree(), and writes those to klList(y). It is assumed that y <= inverse(y). The only error that can occur here is memory overflow because of the allocation for new polynomials in klTree(). In that case, the error is treated, and ERROR_WARNING is set. */ { KLRow& kl_row = klList(y); for (Ulong j = 0; j < kl_row.size(); ++j) { if (kl_row[j]) continue; const KLPol* q = klTree().find(pol[j]); if (q == 0) { /* an error occurred */ Error(ERRNO); ERRNO = ERROR_WARNING; return; } kl_row[j] = q; status().klcomputed++; } return; } void KLContext::KLHelper::writeMuRow(const MuRow& row, const Generator& s, const CoxNbr& y) /* This function writes down row to the corresponding row in the mu-table for s, omitting the zero terms. */ { /* count non-zero terms */ Ulong count = 0; for (Ulong j = 0; j < row.size(); ++j) { const MuPol* pol = row[j].pol; if (!pol->isZero()) count++; } /* copy non-zero terms to row in mu-table */ MuTable& t = muTable(s); delete t[y]; t[y] = new MuRow(0); MuRow& mu_row = *t[y]; mu_row.setSize(count); count = 0; for (Ulong j = 0; j < row.size(); ++j) { const MuPol* pol = row[j].pol; if (!pol->isZero()) { /* append new element */ mu_row[count] = row[j]; count++; } } return; } }; /***************************************************************************** Chapter III -- The KLPol class. The KLPol class is derived form LaurentPolynomial, because we want to re-define the arithmetic operations so that overflow is carefully checked. This makes them expensive, but arithmetic is only used when the polynomials are defined, and there we have to check anyway. The following functions are defined : - add(p,n) : adds p shifted by n to the current polynomial; - subtract(p,mp,n) : subtracts from the current polynomial the product of p and the MuPol mp, shifted by n; *****************************************************************************/ namespace uneqkl { KLPol& KLPol::add(const KLPol& p, const long& n) /* Increments the polynomial by p shifted by n, i.e. X^n.p, while checking that the coefficients of the result remain within bounds. NOTE : a correct implementation would check beforehand the size of the result, so as not to waste memory; we are content with setting the size to the correct value after the fact. This doesn't matter as this function will be used only on temporaries. */ { /* set degree and valuation of the result */ if (deg() < p.deg()+n) { setDeg(p.deg()+n); } for (Degree j = 0; j <= p.deg(); ++j) { safeAdd((*this)[j+n],p[j]); if (ERRNO) return *this; } reduceDeg(); return *this; } KLPol& KLPol::subtract(const KLPol& p, const MuPol& mp, const Ulong& n) /* This function subtracts from the current polynomial the polynomial p*mu shifted by q^{n/2}. Here mp is a MuPol, i.e., a Laurent polynomial in q^{1/2}; it is assumed that n is such that mp*q^{n/2} is a polynomial in q. It is known that for unequal parameters, negative coefficients can occur in K-L polynomials. So we only check for overflow during the computation, and set the error KLCOEFF_OVERFLOW or KLCOEFF_UNDERFLOW accordingly. */ { KLPol q(0); q.setDeg((mp.deg()+n)/2); for (long j = mp.val(); j <= mp.deg(); ++j) { if (mp[j] == 0) continue; /* if we get here, n + j is even */ q[(n+j)/2] = mp[j]; } /* compute the product and check for overflow */ for (Ulong i = 0; i <= q.deg(); ++i) { if (q[i] == 0) continue; for (Ulong j = 0; j <= p.deg(); ++j) { SKLCoeff a = p[j]; safeMultiply(a,q[i]); if (ERRNO) return *this; if (isZero() || (i+j) > deg()) setDeg(i+j); safeAdd(v[i+j],-a); if (ERRNO) return *this; } } reduceDeg(); return *this; } }; /**************************************************************************** Chapter IV -- Kazhdan-Lustig bases. This section defines functions returning Kazhdan-Lusztig bases. Note that the coefficients of these bases should actually be Laurent polynomials; however we (perhaps mistakenly) leave it for now to the output functions to do the shifting that is required; this saves us from introducing a new type at this point. The following functions are defined : - cBasis(h,y,kl) : also called sometimes the C'-basis; in our opinion, the right choice of basis; ****************************************************************************/ namespace uneqkl { void cBasis(HeckeElt& h, const CoxNbr& y, KLContext& kl) /* This is what in the original Kazhdan-Lusztig paper is called the C'-basis, but is now usually denoted c. The C-basis from the K-L paper doesn't seem worth implementing. */ { const SchubertContext& p = kl.schubert(); BitMap b(0); p.extractClosure(b,y); BitMap::Iterator b_end = b.end(); h.setSize(0); for (BitMap::Iterator x = b.begin(); x != b_end; ++x) { const KLPol& pol = kl.klPol(*x,y); HeckeMonomial m(*x,&pol); h.append(m); } return; } }; /***************************************************************************** Chapter V -- Utilities. This section defines some utility functions for this module : - errorPol() : returns an error value; - one() : returns the k-l polynomial 1; - positivePart(p,q,d,m) : returns in p the positive part of q with u^d substituted and shifted by m; - zero() : returns the Laurent polynomial 0; *****************************************************************************/ namespace uneqkl { const MuPol& errorMuPol() { static MuPol p(SKLCOEFF_MIN-1,MuPol::const_tag()); /* cannot be a legal polynomial */ return p; } const KLPol& errorPol() { static KLPol p(SKLCOEFF_MIN-1,KLPol::const_tag()); /* cannot be a legal polynomial */ return p; } const KLPol& one() { static KLPol p(1,KLPol::const_tag()); return p; } }; namespace { void muSubtraction(KLPol& p, const MuPol& mp, const KLPol& q, const Ulong& d, const long& m) /* This function is an auxiliary to fillMu. It subtracts from p, which is destined to hold the positive part of a mu-polynomial, the positive part of mp*r, where r is q with u^d substituted and shifted by m. Forwards an error if there is overflow or underflow of the coefficients. NOTE : it is assumed that mp is non-zero! */ { MuPol r(d*q.deg()+m,m); r.setDegValue(d*q.deg()+m); for (long j = 0; j <= static_cast(q.deg()); ++j) { r[d*j+m] = q[j]; } for (long j = mp.val(); j <= mp.deg(); ++j) { if (!mp[j]) continue; for (long i = r.val(); i <= r.deg(); ++i) if (i+j >= 0) { SKLCoeff a = mp[j]; safeMultiply(a,r[i]); if (ERRNO) return; if (p.isZero() || (i+j) > static_cast(p.deg())) p.setDeg(i+j); safeAdd(p[i+j],-a); if (ERRNO) return; } } p.reduceDeg(); return; } void positivePart(KLPol& p, const KLPol& q, const Ulong& d, const long& m) /* Puts in p the positive part (i.e. the part with positive degree) of the Laurent polynomial obtained by substituting u^d in q, then shifting by u^m. */ { p.setZero(); /* compute degree of result */ long h = q.deg()*d + m; if (h < 0) return; p.setDeg(h); p.setZero(h+1); for (Degree j = q.deg()+1; j;) { --j; p[h] = q[j]; h -= d; if (h < 0) break; } return; } const MuPol* writeMu(BinaryTree& t, const KLPol& p) /* This function symmetrizes p and returns it address on the mutree. */ { MuPol mp; if (p.isZero()) mp.setZero(); else { mp.setBounds(p.deg(),-p.deg()); mp[0] = p[0]; for (long j = 1; j <= static_cast(p.deg()); ++j) { mp[-j] = p[j]; mp[j] = p[j]; } } return t.find(mp); } }; namespace uneqkl { const MuPol& zero() { static MuPol p(0,MuPol::const_tag()); return p; } }; positivity_final/uneqkl.h0000600000175000017500000001527510011372031017300 0ustar duclouxducloux00000000000000/* This is uneqkl.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef UNEQKL_H /* guard against multiple inclusions */ #define UNEQKL_H #include "globals.h" namespace uneqkl { using namespace globals; }; /******** type declarations **************************************************/ #include "coxtypes.h" #include "hecke.h" #include "klsupport.h" #include "list.h" #include "polynomials.h" namespace uneqkl { using namespace coxtypes; using namespace hecke; using namespace klsupport; using namespace list; using namespace polynomials; }; namespace uneqkl { class KLContext; class KLPol; class MuPol; struct KLStatus; struct MuData; typedef List KLRow; typedef List MuRow; typedef List MuTable; typedef List > HeckeElt; }; /******** function declarations **********************************************/ namespace uneqkl { void cBasis(HeckeElt& h, const CoxNbr& y, KLContext& kl); const MuPol& errorMuPol(); const KLPol& errorPol(); const KLPol& one(); const MuPol& zero(); }; /******** type definitions ***************************************************/ #include "bits.h" #include "memory.h" #include "search.h" namespace uneqkl { using namespace bits; using namespace memory; using namespace search; }; namespace uneqkl { class KLPol:public Polynomial { static const SKLCoeff min_coeff = SKLCOEFF_MIN; static const SKLCoeff max_coeff = SKLCOEFF_MAX; public: static PolynomialType polType() {return UNEQ_KLPOL;} KLPol() {}; KLPol(const Ulong& n):Polynomial(n) {}; KLPol(const SKLCoeff& c, const_tag):Polynomial(c,const_tag()) {}; ~KLPol() {}; KLPol& add(const KLPol& p, const long& n); KLPol& subtract(const KLPol& p, const MuPol& mp, const Ulong& n); }; class MuPol:public LaurentPolynomial { public: struct const_tag {}; MuPol() {}; MuPol(const SDegree& d, const SDegree& o = 0) :LaurentPolynomial(d,o) {}; MuPol(const SKLCoeff& c, const_tag):LaurentPolynomial(0,0) {d_pol.setDegValue(0); d_pol[0] = c;} ~MuPol() {}; }; struct MuData { CoxNbr x; const MuPol* pol; /* constructors anc destructors*/ void operator delete(void* ptr) {return arena().free(ptr,sizeof(MuData));} MuData() {}; MuData(const CoxNbr& x, const MuPol* pol):x(x),pol(pol) {}; /* comparison */ bool operator> (const MuData& m) const; /* inlined */ bool operator< (const MuData& m) const; /* inlined */ bool operator== (const MuData& m) const; /* inlined */ }; struct KLStatus { Ulong klrows; Ulong klnodes; Ulong klcomputed; Ulong murows; Ulong munodes; Ulong mucomputed; Ulong muzero; /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLStatus));} KLStatus() {}; ~KLStatus() {}; }; class KLContext { KLSupport* d_klsupport; List d_klList; List d_muTable; List d_L; /* lengths of generators */ List d_length; /* lengths of context elements */ BinaryTree d_klTree; BinaryTree d_muTree; KLStatus* d_status; struct KLHelper; /* provides helper functions */ KLHelper* d_help; friend struct KLHelper; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(KLContext));} KLContext(KLSupport* kls, const CoxGraph& G, const Interface& I); ~KLContext(); /* accessors */ const ExtrRow& extrList(const CoxNbr& y) const; /* inlined */ Ulong genL(const Generator& s) const; /* inlined */ CoxNbr inverse(const CoxNbr& x) const; /* inlined */ bool isKLAllocated(const CoxNbr& y) const; /* inlined */ bool isMuAllocated(const Generator& s, const CoxNbr& y) const; /* inlined */ const KLRow& klList(const CoxNbr& y) const; /* inlined */ const KLSupport& klsupport() const; /* inlined */ Generator last(const CoxNbr& x) const; /* inlined */ Ulong length(const CoxNbr& x) const; /* inlined */ const MuRow& muList(const Generator& s, const CoxNbr& y) const;/* inlined */ Rank rank() const; /* inlined */ const SchubertContext& schubert() const; /* inlined */ Ulong size() const; /* inlined */ /* modifiers */ void applyInverse(const CoxNbr& y); void applyIPermutation(const CoxNbr& y, const Permutation& a); /* inlined */ void fillKL(); void fillMu(); void fillMu(const Generator& s); const KLPol& klPol(const CoxNbr& x, const CoxNbr& y); const MuPol& mu(const Generator& s, const CoxNbr& x, const CoxNbr& y); void row(HeckeElt& h, const CoxNbr& y); void permute(const Permutation& a); void revertSize(const Ulong& n); void setSize(const Ulong& n); }; }; /******** inline definitions ************************************************/ namespace uneqkl { inline bool MuData::operator> (const MuData& m) const {return x > m.x;} inline bool MuData::operator< (const MuData& m) const {return x < m.x;} inline bool MuData::operator== (const MuData& m) const {return x == m.x;} inline const ExtrRow& KLContext::extrList(const CoxNbr& y) const {return klsupport().extrList(y);} inline Ulong KLContext::genL(const Generator& s) const {return d_L[s];} inline CoxNbr KLContext::inverse(const CoxNbr& x) const {return klsupport().inverse(x);} inline bool KLContext::isKLAllocated(const CoxNbr& y) const {return d_klList[y] != 0;} inline bool KLContext::isMuAllocated(const Generator& s, const CoxNbr& y) const {return (*d_muTable[s])[y] != 0;} inline const KLRow& KLContext::klList(const CoxNbr& y) const {return *d_klList[y];} inline const KLSupport& KLContext::klsupport() const {return *d_klsupport;} inline Generator KLContext::last(const CoxNbr& x) const {return klsupport().last(x);} inline Ulong KLContext::length(const CoxNbr& x) const {return d_length[x];} inline const MuRow& KLContext::muList(const Generator& s, const CoxNbr& y) const {return d_muTable[s][0][y][0];} inline Rank KLContext::rank() const {return d_klsupport->rank();} inline const SchubertContext& KLContext::schubert() const {return klsupport().schubert();} inline Ulong KLContext::size() const {return d_klList.size();} inline void KLContext::applyIPermutation(const CoxNbr& y, const Permutation& a) {return rightRangePermute(*d_klList[y],a);} }; #endif positivity_final/vector.cpp0000600000175000017500000000000010011171251017613 0ustar duclouxducloux00000000000000positivity_final/vector.h0000600000175000017500000000704310012721342017301 0ustar duclouxducloux00000000000000/* This is vector.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef VECTOR_H /* guarantee unique inclusion */ #define VECTOR_H #include "globals.h" namespace vector { using namespace globals; }; /* type declarations */ namespace vector { template class Vector; }; /********* implementation **************************************************/ #include "io.h" #include "list.h" #include "memory.h" namespace vector { using namespace io; using namespace list; using namespace memory; }; namespace vector { template class Vector { private: List d_list; public: /* constructors and destructors */ Vector(){}; Vector(Ulong n):d_list(n) {}; Vector(const Vector& w):d_list(w.list()) {}; Vector(T* const& ptr, const Ulong& n):d_list(ptr,n) {}; Vector(T* const& ptr, const Ulong& n, bool b):d_list(ptr,n,b) {}; ~Vector() {}; /* manipulators */ T& operator[] (const Ulong& j); const Vector& operator= (const Vector& w); Vector& operator+= (const Vector& w); Vector& operator-= (const Vector& w); Vector& operator*= (const T& a); Vector& operator- (); Ulong& dim() {return d_list.size();} T* ptr(); void reduceDim(); void setDim(const Ulong& n); /* inlined */ void setDimValue(const Ulong& n); /* inlined */ void setVect(const T *source, const Ulong& first, const Ulong& r); /* inlined */ void setVect(const T *source, const Ulong& r); /* inlined */ void setZero(const Ulong& first, const Ulong& r); /* inlined */ void setZero(const Ulong& r); /* inlined */ void setZero(); /* inlined */ /* accessors */ const T& operator[] (const Ulong& j) const; const Ulong& dim() const; const List& list() const; const T* ptr() const; }; }; /* inline implementations */ namespace vector { template inline const Vector& Vector::operator= (const Vector& w) {d_list.assign(w.list()); return *this;} template inline T* Vector::ptr() {return d_list.ptr();} template inline void Vector::setDim(const Ulong& n) {Ulong d = dim(); d_list.setSize(n); if (n>d) setZero(d,n-d);} template inline void Vector::setDimValue(const Ulong& n) {d_list.setSizeValue(n);} template inline void Vector::setVect(const T *source, const Ulong& first, const Ulong& r) {d_list.setData(source,first,r);} template inline void Vector::setVect(const T *source, const Ulong& r) {setVect(source,0,r);} template inline void Vector::setZero(const Ulong& first, const Ulong& r) {d_list.setZero(first,r);} template inline void Vector::setZero(const Ulong& r) {d_list.setZero(0,r);} template inline void Vector::setZero() {d_list.setZero();} template inline T& Vector::operator[] (const Ulong& j) {return d_list[j];} template inline const T& Vector::operator[] (const Ulong& j) const {return d_list[j];} template inline const Ulong& Vector::dim() const {return d_list.size();} template inline const List& Vector::list() const {return d_list;} template inline const T* Vector::ptr() const {return d_list.ptr();} }; #include "vector.hpp" #endif positivity_final/vector.hpp0000600000175000017500000000442610012472352017647 0ustar duclouxducloux00000000000000/* This is vector.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ /**************************************************************************** This module contains the implementation of the vector template. Just as for lists, we define vectors only for types where copy-constructors are simply bitwise copy; i.e., vectors are really strings. Otheerwise, a vector is a list of elements in a class for which ring operations are defined. ****************************************************************************/ /**************************************************************************** Chapter I --- The Vector class This section contains the definition of the functions for the Vector class : - operator+=(w) : adds w to the current vector; - operator-=(w) : subtracts w from the current vector; - operator*=(a) : multiplies the current vector by the scalar a; - reduceDim() : reduces the dimension; ****************************************************************************/ namespace vector { template Vector& Vector::operator+= (const Vector& w) /* Operator += for Vectors always makes sure that there is enough space. */ { if (w.dim() > dim()) /* enlarge v if necessary and extend by zero */ setDim(w.dim()); for (Ulong j = 0; j < w.dim(); j++) d_list[j] += w[j]; return *this; } template Vector& Vector::operator-= (const Vector& w) /* Operator -= for Vectors always makes sure that there is enough space. */ { unsigned long j; if (w.dim() > dim()) /* enlarge v if necessary and extend by zero */ setDim(w.dim()); for (Ulong j = 0; j < w.dim(); j++) d_list[j] -= w[j]; return *this; } template Vector& Vector::operator*= (const T& a) /* Scalar multiplication operator. */ { for (Ulong j = 0; j < dim(); j++) d_list[j] *= a; return *this; } template void Vector::reduceDim() /* This function reduces the dimension to the smallest value that will contain all non-zero coefficients in the current vector. */ { for (Ulong j = dim(); j;) { j--; if (d_list[j]) { d_list.setSize(j+1); return; } } d_list.setSize(0); return; } }; positivity_final/version.h0000600000175000017500000000047010011171251017456 0ustar duclouxducloux00000000000000/* This is version.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef VERSION_H /* guard against multiple inclusions */ #define VERSION_H namespace version { char* const NAME = "Coxeter"; char* const VERSION = "3.0_alpha2"; }; #endif positivity_final/wgraph.cpp0000600000175000017500000003403010011171251017613 0ustar duclouxducloux00000000000000/* This is wgraph.cpp Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #include "wgraph.h" #include "stack.h" /**************************************************************************** This module contains code for the implementation of W-graphs. Recall that for a given Coxeter group W, a W-graph is the datum of a graph, together with a labelling of the vertices by subsets of the generating set S of W, and a labelling of the (oriented) edges by integers mu(x,y); these data have to be such that certain explicit formulae define a representation of the Hecke algebra of W on the free Z[q^{1/2},q^{-1/2}]-module generated by the vertices of the graph. Of course the main source of such graphs (the only one in this program) is from (subsets of) the group W itself, where the subsets of S are descent sets, and the mu(x,y) come from the k-l polynomials. We are interested in the following problems : - decompose a given graph in cells; - compare graphs up to isomorphism; - find the cells in a graph up to isomorphism; - check if a graph is a W-graph; ****************************************************************************/ namespace { using namespace wgraph; using namespace stack; void getClass(const OrientedGraph& X, const Vertex& y, BitMap& b, Partition& pi, OrientedGraph* P = 0); }; /**************************************************************************** Chapter I -- The WGraph class Recall that a W-graph is an oriented graph, together with the datum of a subset of the generating set S for each vertex, and a coefficient mu(x,y) for each edge, so that certain formulae (abstracted from the formulae that give the action of the standard generators of the Hecke algebra on the k-l basis) yield a representation of the Hecke algebra. In particular, such graphs (left,right,and two-sided) are defined on the full group W, and their restriction to left (right,two-sided) cells is again a W-graph. In our implementation, we have separated the oriented graph proper from the subsets and coefficients; this is reasonable as some important computations, such as the determination of the cells, only use the graph structure, and moreover are most naturally implemented (and will actually be used later on) in the setting of abstract graphs. The following functions are defined : - constructors and destructors : - WGraph(n) : allocates a W-graph with n vertices, no edges; - ~WGraph() : destructor; - accessors : - edge(x) : returns a reference to the list of edges originating from x (inlined); - graph() : returns a constant reference to the graph (inlined); - size() : returns the number of vertices (inlined); - modifiers : - graph() : returns a non-constant reference to the graph (inlined); - reset() : resets the structure; - setSize(const Ulong &n) : sets the size to n; - input/output : - print(file) : prints the graph on a file in ascii format; ****************************************************************************/ namespace wgraph { WGraph::WGraph(const Ulong& n):d_coeff(n),d_descent(n) /* Constructor for the WGraph class. */ { d_graph = new OrientedGraph(n); } WGraph::~WGraph() /* The only non-automatic part is the deletion of d_graph. */ { delete d_graph; } void WGraph::reset() /* This function resets the structure to an empty graph of the same size. */ { d_graph->reset(); d_coeff.setZero(); d_descent.setZero(); return; } void WGraph::setSize(const Ulong& n) /* Sets the sizes of the data structures so that the graph can accomodate n vertices. */ { d_graph->setSize(n); d_coeff.setSize(n); d_descent.setSize(n); return; } void WGraph::print(FILE* file, const Interface& I) const /* Prints the graph on a file in ascii format. */ { const OrientedGraph& Y = *d_graph; int d = digits(size()-1,10); /* count number of edges */ Ulong count = 0; for (Vertex x = 0; x < size(); ++x) { const EdgeList& e = Y.edge(x); count += e.size(); } // find alignement String str(0); LFlags f = leqmask[I.rank()-1]; interface::append(str,f,I); Ulong descent_maxwidth = str.length(); fprintf(file,"%lu vertices, %lu edges\n\n",size(),count); for (Vertex x = 0; x < size(); ++x) { fprintf(file,"%*lu : ",d,x); io::reset(str); interface::append(str,descent(x),I); pad(str,descent_maxwidth ); io::print(file,str); fprintf(file," "); const EdgeList e = Y.edge(x); const CoeffList c = coeffList(x); for (Ulong j = 0; j < e.size(); ++j) { fprintf(file,"%lu(%lu)",e[j],static_cast(c[j])); if (j+1 < e.size()) /* there is more to come */ fprintf(file,","); } fprintf(file,"\n"); } } }; /**************************************************************************** Chapter II -- The OrientedGraph class. An oriented graph is just a set of vertices, and for each vertex, a list of vertices representing the edges originating from that vertex. The following functions are defined : - constructors and destructors : - OrientedGraph(n) : initializes a graph with n vertices and no edges (inlined); - ~OrientedGraph() : destructor; - accessors : - cells(pi) : puts in pi the partition corresponding to the cells in the graph; - edge(x) : returns a constant reference to the list of edges originating from x (inlined); - size() : returns the number of vertices (inlined); - normalPermuation(a) : gives the permutation to a normalized form; - print() : prints out the graph; - modifiers : - edge(x) : returns a non-copnstant reference to the list of edges originating from x (inlined); - permute(a) : permutes the graph according to a; - reset() : resets the structure; - setSize(n) : sets the size of the data to accomodate n vertices (inlined); ****************************************************************************/ namespace wgraph { OrientedGraph::~OrientedGraph() /* Destruction is automatic. */ {} void OrientedGraph::cells(Partition& pi, OrientedGraph* P) const /* Define a preorder relation on the vertices by setting x <= y iff there is an oriented path from x to y. This function puts in pi the partition function corresponding to the equivalence classes of this preorder. We use the Tarjan algorithm, explained in one of the Knuth books, but which I learned from Bill Casselman. The vertices for which the partition function is already defined will be said to be dealt with. These are marked off in an auxiliary bitmap. The algorithm goes as follows. Start with the first vertex that has not been dealt with, say x0. We will have to deal (potentially) with the set of all vertices visible from x0 (i.e >= x0). There will be a stack of vertices, corresponding to a path originating from x0, such that at each point in time, each vertex y >= x0 which is not dealt with will be equivalent to an element of the stack; the least such (in the stack ordering) will be called y_min, so that for instance x0_min = 0. We record these values in an additional table, initialized to some value undefined. Now let x be at the top of the stack. Look at the edges originating from x. Ignore the ones that go to vertices which are dealt with. If there are no edges left, x is minimal and is a class by itself; we can take it off, mark it as dealt with, and continue. Otherwise, run through the edges one by one. Let the edge be x->y. If y_min is defined, this means that y has already been examined, and is not dealt with. But each such element is equivalent to an element in the active stack, so y_min should be one of the elements in the active stack, hence x is visible from y_min: in other words, x and y are equivalent, and we set x_min = y_min if y_min < x_min. Otherwise, y is seen for the first time; then we just put it on the stack. When we are done with the edges of x, we have now the value of x_min which is the inf over the edges originating from x of the y_min. If this value is equal to the stack-position of x, we see that x is minimal in its class, and we get a new class by taking all the successors of x not already dealt with. We then move to the parent of x and continue the process there. */ { static Permutation a(0); static BitMap b(0); static List v(1); static List elist(1); static List ecount(1); static List min(0); pi.setSize(size()); pi.setClassCount(0); b.setSize(size()); b.reset(); min.setSize(size()); min.setZero(); for (Vertex x = 0; x < size(); ++x) min[x] = size(); for (Vertex x = 0; x < size(); ++x) { if (b.getBit(x)) /* x is dealt with */ continue; v[0] = x; v.setSize(1); elist[0] = &edge(x); elist.setSize(1); ecount[0] = 0; ecount.setSize(1); min[x] = 0; Ulong t = 1; while(t) { Vertex y = v[t-1]; Vertex z; const EdgeList& e = *elist[t-1]; for (; ecount[t-1] < e.size(); ++ecount[t-1]) { z = e[ecount[t-1]]; if (b.getBit(z)) continue; if (min[z] == size()) /* z is new */ goto add_path; if (min[y] > min[z]) min[y] = min[z]; } /* at this point we have exhausted the edges of y */ if (min[y] == t-1) { /* take off class */ getClass(*this,y,b,pi,P); } else if (min[y] < min[v[t-2]]) /* if t=1, previous case holds */ min[v[t-2]] = min[y]; t--; continue; add_path: v.setSize(t+1); elist.setSize(t+1); ecount.setSize(t+1); v[t] = z; elist[t] = &edge(z); ecount[t] = 0; min[z] = t; t++; } } return; } void OrientedGraph::levelPartition(Partition& pi) const /* Assuming the graph has no oriented cycles, this function writes in pi the partition of the vertices according to their level, where sinks have level 0, then sinks in the remaining poset have level one, etc. NOTE : the implementation is simple-minded : we traverse the graph as many times as there are levels. */ { static BitMap b(0); static BitMap b1(0); b.setSize(size()); b.reset(); b1.setSize(size()); b1.reset(); pi.setSize(size()); Ulong count = 0; Ulong current_level = 0; while (count < size()) { for (SetElt x = 0; x < size(); ++x) { if (b.getBit(x)) continue; const EdgeList e = d_edge[x]; for (Ulong j = 0; j < e.size(); ++j) { if (!b.getBit(e[j])) /* next x */ goto nextx; } /* i we get here, x is the next element in the permutation */ pi[x] = current_level; b1.setBit(x); ++count; nextx: continue; } b.assign(b1); current_level++; } pi.setClassCount(current_level); return; } void OrientedGraph::permute(const Permutation& a) /* This function permutes the graph according to the permutation a, according to the usual rule : the edges of a(x) should be the image under a of the edge set of x. As usual, permuting values is easy : it is enough to apply a to the elements in the various edgelists. Permuting ranges is trickier, because it involves a^-1. It is assumed of course that a holds a permutation of size size(). */ { static BitMap b(0); static EdgeList e_buf(0); /* permute values */ for (SetElt x = 0; x < size(); ++x) { EdgeList& e = d_edge[x]; for (Ulong j = 0; j < e.size(); ++j) { e[j] = a[e[j]]; } } /* permute ranges */ b.setSize(size()); b.reset(); for (SetElt x = 0; x < size(); ++x) { if (b.getBit(x)) continue; if (a[x] == x) { /* fixed point */ b.setBit(x); continue; } for (SetElt y = a[x]; y != x; y = a[y]) { /* back up values for y */ e_buf.shallowCopy(d_edge[y]); /* put values for x in y */ d_edge[y].shallowCopy(d_edge[x]); /* store backup values in x */ d_edge[x].shallowCopy(e_buf); /* set bit */ b.setBit(y); } b.setBit(x); } } void OrientedGraph::print(FILE* file) const /* Does a printout of the graph on the file. */ { fprintf(file,"size : %lu\n\n",size()); int d = digits(size(),10); for (Vertex x = 0; x < size(); ++x) { const EdgeList& e = edge(x); fprintf(file,"%*lu : ",d,x); for (Ulong j = 0; j < e.size(); ++j) { fprintf(file,"%*lu",d,e[j]); if (j < e.size()-1) { /* there is more to come */ fprintf(file,","); } } fprintf(file,"\n"); } fprintf(file,"\n"); return; } void OrientedGraph::reset() /* Resets the structure to hold a edge-less graph of the same size. */ { for (Ulong j = 0; j < size(); ++j) { d_edge[j].setSize(0); } return; } }; /**************************************************************************** Chapter III -- Auxiliaries This chapter contains some auxiliary functions for the main functions in this module. The following functions are defined : - getClass(X,y,b) : gets the class of y in X, using the bitmap b; ****************************************************************************/ namespace { void getClass(const OrientedGraph& X, const Vertex& y, BitMap& b, Partition& pi, OrientedGraph* P) /* After the element y has been identified as minimal among the elements not already marked in b, this function marks off the equivalence class of y; these are just the elements visible from y and not already marked in b. The class is also written as a new class in pi. */ { static Fifo c; Ulong a = pi.classCount(); c.push(y); b.setBit(y); pi[y] = a; if (P) P->setSize(a+1); while (c.size()) { Vertex x = c.pop(); const EdgeList& e = X.edge(x); for (Ulong j = 0; j < e.size(); ++j) { Vertex z = e[j]; if (b.getBit(z)) { if (P && (pi[z] < a)) { /* add a new edge to P */ EdgeList& f = P->edge(a); if (find(f,pi[z]) == not_found) { /* edge is new */ insert(f,pi[z]); } } continue; } else { c.push(z); b.setBit(z); pi[z] = a; } } } pi.setClassCount(a+1); return; } }; positivity_final/wgraph.h0000600000175000017500000000756010115327076017305 0ustar duclouxducloux00000000000000/* This is wgraph.h Coxeter version 3.0 Copyright (C) 2002 Fokko du Cloux See file main.cpp for full copyright notice */ #ifndef WGRAPH_H /* guard against multiple inclusions */ #define WGRAPH_H #include "globals.h" #include "list.h" namespace wgraph { using namespace globals; using namespace list; }; /******** type declarations *************************************************/ namespace wgraph { class WGraph; class OrientedGraph; typedef Ulong Vertex; typedef unsigned short Coeff; typedef List CoeffList; typedef Vertex Edge; typedef List EdgeList; }; /******** type definitions **************************************************/ #include "bits.h" #include "interface.h" namespace wgraph { using namespace bits; using namespace interface; }; class wgraph::OrientedGraph { private: List d_edge; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(OrientedGraph));} OrientedGraph(const Ulong &n):d_edge(n) {}; ~OrientedGraph(); /* accessors */ void cells(Partition& pi, OrientedGraph* P = 0) const; const EdgeList& edge(const Vertex& x) const; /* inlined */ Vertex firstMinimal(const BitMap& b) const; void levelPartition(Partition& pi) const; void print(FILE* file) const; Ulong size() const; /* inlined */ /* modifiers */ EdgeList& edge(const Vertex& x); /* inlined */ void permute(const Permutation& a); void reset(); void setSize(const Ulong& n); /* inlined */ }; class wgraph::WGraph { private: OrientedGraph* d_graph; List d_coeff; List d_descent; public: /* constructors and destructors */ void* operator new(size_t size) {return arena().alloc(size);} void operator delete(void* ptr) {return arena().free(ptr,sizeof(WGraph));} WGraph(const Ulong &n); ~WGraph(); /* accessors */ const CoeffList& coeffList(const Vertex& x) const; /* inlined */ const LFlags& descent(const Vertex& x) const; /* inlined */ const EdgeList& edge(const Vertex& x) const; /* inlined */ const OrientedGraph& graph() const; /* inlined */ Ulong size() const; /* inlined */ /* modifiers */ CoeffList& coeffList(const Vertex& x); /* inlined */ LFlags& descent(const Vertex& x); /* inlined */ EdgeList& edge(const Vertex& x); /* inlined */ OrientedGraph& graph(); /* inlined */ void reset(); void setSize(const Ulong& n); /* input/output */ void print(FILE* file, const Interface& I) const; }; namespace wgraph { inline const CoeffList& WGraph::coeffList(const Vertex& x) const {return d_coeff[x];} inline const LFlags& WGraph::descent(const Vertex& x) const {return d_descent[x];} inline const EdgeList& WGraph::edge(const Vertex& x) const {return d_graph->edge(x);} inline const OrientedGraph& WGraph::graph() const {return *d_graph;} inline CoeffList& WGraph::coeffList(const Vertex& x) {return d_coeff[x];} inline EdgeList& WGraph::edge(const Vertex& x) {return d_graph->edge(x);} inline Ulong WGraph::size() const {return d_graph->size();} inline OrientedGraph& WGraph::graph() {return *d_graph;} inline LFlags& WGraph::descent(const Vertex& x) {return d_descent[x];} inline const EdgeList& OrientedGraph::edge(const Vertex& x) const {return d_edge[x];} inline Ulong OrientedGraph::size() const {return d_edge.size();} inline EdgeList& OrientedGraph::edge(const Vertex& x) {return d_edge[x];} inline void OrientedGraph::setSize(const Ulong& n) {d_edge.setSize(n);} }; #endif positivity_final/headers/0000700000175000017500000000000010001264550017234 5ustar duclouxducloux00000000000000positivity_final/headers/terse_generators0000600000175000017500000000066507772643515022572 0ustar duclouxducloux00000000000000# # Generators in the group are represented by decimal numbers 1,2, ... ; the # ordering of the generators is the current ordering. Unless you have changed # that, the format for outputting group elements as words is the same as for # GAP, viz. prefix "[", separator ",", postfix "]"; so for instance a word in # three generators that would be written as 12321 in our usual "really terse" # style will be written here as [1,2,3,2,1]. positivity_final/headers/GAPclosure20000600000175000017500000000003207730364457021270 0ustar duclouxducloux00000000000000## ## Critical pairs : ## positivity_final/headers/GAPclosure10000600000175000017500000000133607772637057021304 0ustar duclouxducloux00000000000000## ## It contains information about the schubert variety corresponding to a ## element y. The following data are given : a reduced expression of y; ## the complete list of all "critical pairs" (x,y), as defined in the ## Chevie manual (called "extremal pairs" within Coxeter), and their ## corresponding Kazhdan-Lusztig polynomials; the singular locus of ## the schubert variety; and the rational singular stratification. ## ## All group elements are represented by reduced expressions in GAP format, ## i.e. a left bracket [, followed by a comma-separated list of the ## generators in the expression in decimal notation, and a right bracket ]. ## The numbering of the group generators is bourbaki numbering. ## ## The element y : ## positivity_final/headers/terse_cells20000600000175000017500000000202307777276455021605 0ustar duclouxducloux00000000000000# # This file contains the list of the W-graphs for the various Kazhdan-Lusztig # cells in the group. Each cell is sorted w.r.t the shortlex normal form order # (for the ordering of the generators which was current when this file was # created) and the cells are written in the order of their first elements. # # First we print the lists of the descent sets for the various nodes of the # graphs. We output one line per graph, and on each line a comma-separated # set of lists of the form (*,*,...,*) where the * are the descent generators. # # Then we print the list of edge-lists, again one line per graph. There is # one edge-list per node of the graph; it is a brace-enclosed, comma-separated # list of pairs (destination,mu) where destination is the destination of # the edge, represented by the index number of the destination node, starting # from zero, in the node numbering that we use, and mu is the corresponding # mu-coefficient. # # The two lists are separated by a comment line saying "edge lists", to # make parsing easier. # positivity_final/headers/GAPduflo0000600000175000017500000000065710000533545020634 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_duflo of the list ## of all Duflo involutions in the current group, together with the ## corresponding Kazhdan-Lusztig polynomials P_{e,d} (recall that a ## Duflo involution d is the unique element in its left cell for which ## l(d) - 2 deg(P_{e,d}) is minimal.) ## ## The involutions are output in the same order as the left cells are ## output by the "lcells" command. ## positivity_final/headers/GAPbasis0000600000175000017500000000135007776577555020656 0ustar duclouxducloux00000000000000## ## Let H := Hecke(W,u^2,u) be the Hecke algebra of our group, where u is ## a square root of our indeterminate q. Then this file contains one GAP ## instruction, the assignment to the variable coxeter_cbasis of what would be ## the GAP output to the call t(c(w)) in Chevie, where w is our element (which ## can be read as the last term in the file), t is u^{-l(w)}T(w), where ## T := Basis(H,"T") is the ordinary basis of the Hecke algebra, and ## c := Basis(H,"C'") is what was called the C'-basis in the original ## Kazhdan-Lusztig paper. ## ## The coefficients are shifted as they should, and are therefore polynomials ## in the negative powers of the indeterminate u. The powers that come up are ## either all even or all odd. ## positivity_final/headers/GAPclosure30000600000175000017500000000010107730622433021255 0ustar duclouxducloux00000000000000## ## Irreducible components of the rational singular locus : ## positivity_final/headers/GAPlrcorder0000600000175000017500000000176110000214207021323 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lrcorder of the ## order relation on the tow-sided cells, inherited from the preorder relation ## <=_LR on the group. What we output is the hasse diagram of this ordering ## (or rather of the dual ordering) : for each cell, we print the list ## of cells that lie immediately above it (recall that {e} is the *largest* ## element in the two-sided cell ordering.) As always, cells are represented ## by their index number in the list which is output by lcells; in this ## file, we produce the abstract ordering on the integers {1, ..., N}, where ## N is the number of two-sided cells. ## ## Note that the enumeration ordering we use on cells is not compatible with ## the (reversed) two-sided cell ordering, in the sense that edges in our hasse ## diagram do not always go to elements with a smaller index. It would be ## possible to re-sort the cells so that this would be true, but we have ## refrained from doing that for the sake of consistency. ## positivity_final/headers/GAPclosure40000600000175000017500000000040207730622674021271 0ustar duclouxducloux00000000000000## ## Rational singular stratification : for each k-l polynomial p != 1, we print ## the maximal elements of the set of x <= y s.t. P_{x,y} = p (it is easy to ## see that (x,y) has to be a critical pair.) This gives a rough version of ## equisingularity. ## positivity_final/headers/GAPlrwgraph0000600000175000017500000000213510000162376021342 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lrwgraph of the ## full two-sidedW-graph of the current context. This is guaranteed to ## be a W-graph only when the current context is the full group context; ## otherwise it is the user's responsibility either to ensure that he ## is dealing with a context which is a union of two-sided cells, or to ## get what he can from the partial graph. ## ## In order to be consistent with our other output, we have sorted the ## group elements in shortlex order for the Bourbaki ordering of the ## generators. ## ## For convenience we allocate the enumeration to the variable ## coxeter_contextEnumeration. ## ## The W-graph is represented as a list of pairs [descent set, edge-list], ## one for each element on the context. The descent set is again a pair ## [left descents, right descents]; the edge-list is a list of pairs ## [destination,mu], where mu is the mu-coefficient, and destination is ## the destination of the edge, represented as a number in the enumeration ## of the context that we use (indices start from 1, to be consistent with ## GAP usage.) ## positivity_final/headers/GAPlcorder0000600000175000017500000000173310000212577021150 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lcorder of the ## order relation on the left cells, inherited from the preorder relation ## <=_L on the group. What we output is the hasse diagram of this ordering ## (or rather of the dual ordering) : for each cell, we print the list ## of cells that lie immediately above it (recall that {e} is the *largest* ## element in the left cell ordering.) As always, cells are represented ## by their index number in the list which is output by lcells; in this ## file, we produce the abstract ordering on the integers {1, ..., N}, where ## N is the number of left cells. ## ## Note that the enumeration ordering we use on cells is not compatible with ## the (reversed) left cell ordering, in the sense that edges in our hasse ## diagram do not always go to elements with a smaller index. It would be ## possible to re-sort the cells so that this would be true, but we have ## refrained from doing that for the sake of consistency. ## positivity_final/headers/terse_lcellorder0000600000175000017500000000202007735222775022533 0ustar duclouxducloux00000000000000# # It contains the order relation on the left cells, inherited from the # preorder relation <=_L on the group. What we output is the hasse diagram # of this ordering (or rather of the dual ordering) : for each cell, we # print the list of cells that lie immediately above it (recall that {e} is # the *largest* element in the left cell ordering.) As always, cells are # represented by their index number in the list which is output by lcells; # in this file, we produce the abstract ordering on the integers {0, ..., N-1}, # where N is the number of left cells. # # Note that the enumeration ordering we use on cells is not compatible with # the (reversed) left cell ordering, in the sense that edges in our hasse # diagram do not always go to elements with a smaller index. It would be # possible to re-sort the cells so that this would be true, but we have # refrained from doing that for the sake of consistency. # # We output one edge-list per line, as a comma-separated list; the first line # is an empty list, as it should be! # positivity_final/headers/terse_polynomials0000600000175000017500000000074507735042670022760 0ustar duclouxducloux00000000000000# # Polynomials are represented in dense representation, as a list of # coefficients, starting with the coefficient in degree zero. Lists # are comma-separated and enclosed in parentheses. Polynomials may # be preceded by a modifier of the form (d,m); this means that X^d # has to be substituted in the polynomial, and that the result should # be multiplied by X^m; in particular, this is how Laurent polynomials # are obtained. An absent modifier is equivalent to the modifier (1,0). positivity_final/headers/terse_closure10000600000175000017500000000002607735206613022136 0ustar duclouxducloux00000000000000# # The element y : # positivity_final/headers/terse_closure20000600000175000017500000000016407735207162022142 0ustar duclouxducloux00000000000000# # The critical pairs are output in the format groupelt:polynomial, one element # per line. # # Critical pairs : # positivity_final/headers/terse_basis0000600000175000017500000000231207776602061021504 0ustar duclouxducloux00000000000000# # Polynomials are represented in dense representation, as a list of # coefficients, starting with the coefficient in degree zero. Lists # are comma-separated and enclosed in parentheses. Polynomials may # be preceded by a modifier of the form (d,m); this means that X^d # has to be substituted in the polynomial, and that the result should # be multiplied by X^m; in particular, this is how Laurent polynomials # are obtained. An absent modifier is equivalent to the modifier (1,0). # # The file contains the data for one element c_y of the Kazhdan-Lusztig # c-basis (denoted C' in the original KL paper) of the Hecke algebra # of the group. The coefficients in this basis are polynomials in the # indeterminate u = q^{-1/2}; but after an appropriate shift they become # polynomials in q. Therefore they can be compactly represented with # a modifier of the form (2,-m), m >= 0. We print out one line for # each x <= y in the Bruhat ordering; the line contains the element x, # followed by : and the corresponding polynomial. To find out the value # of y, look at the last line. The elements x are sorted in the shortlex # ordering corresponding to the ordering of generators which was current # when this file was created. positivity_final/headers/GAPclosure50000600000175000017500000000004207735045462021271 0ustar duclouxducloux00000000000000## ## Ordinary Betti numbers : ## positivity_final/headers/terse_duflo0000600000175000017500000000243510000533437021502 0ustar duclouxducloux00000000000000# # This file contains the list of all Duflo (or distinguished) involutions in # the current group, together with the corresponding Kazhdan-Lusztig # polynomials P_{e,d} (recall that a Duflo involution d is the unique element # in its left cell for which l(d) - 2 deg(P_{e,d}) is minimal.) # # Pairs are output in the format involution:polynomial, one pair per line. # The output order is the same as the order in which the left cells are # output by the "lcells" command. # # Generators in the group are represented by decimal numbers 1,2, ... ; # the format for outputting group elements as words is the same as for # GAP, viz. prefix "[", separator ",", postfix "]"; so for instance a word # in three generators that would be written as 12321 in our usual "really # terse" style will be written here as [1,2,3,2,1]. # # Polynomials are represented in dense representation, as a list of # coefficients, starting with the coefficient in degree zero. Lists # are comma-separated and enclosed in parentheses. Polynomials may # be preceded by a modifier of the form (d,m); this means that X^d # has to be substituted in the polynomial, and that the result should # be multiplied by X^m; in particular, this is how Laurent polynomials # are obtained. An absent modifier is equivalent to the modifier (1,0). # positivity_final/headers/GAPclosure60000600000175000017500000000006107735045504021270 0ustar duclouxducloux00000000000000## ## Intersection cohomology Betti numbers : ## positivity_final/headers/terse_closure30000600000175000017500000000007607735207230022141 0ustar duclouxducloux00000000000000# # Irreducible components of the rational singular locus : # positivity_final/headers/terse_closure40000600000175000017500000000037407735207332022146 0ustar duclouxducloux00000000000000# # Rational singular stratification : for each k-l polynomial p != 1, we print # the maximal elements of the set of x <= y s.t. P_{x,y} = p (it is easy to # see that (x,y) has to be a critical pair.) This gives a rough version of # equisingularity. # positivity_final/headers/terse_closure50000600000175000017500000000015107735207747022152 0ustar duclouxducloux00000000000000# # Betti numbers are output as a comma-separated list, on a single line. # # Ordinary Betti numbers : # positivity_final/headers/terse_closure60000600000175000017500000000005607735207554022153 0ustar duclouxducloux00000000000000# # Intersection cohomology Betti numbers : # positivity_final/headers/GAPlcellorder0000600000175000017500000000173607734773763021705 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lcellOrder of the ## order relation on the left cells, inherited from the preorder relation ## <=_L on the group. What we output is the hasse diagram of this ordering ## (or rather of the dual ordering) : for each cell, we print the list ## of cells that lie immediately above it (recall that {e} is the *largest* ## element in the left cell ordering.) As always, cells are represented ## by their index number in the list which is output by lcells; in this ## file, we produce the abstract ordering on the integers {1, ..., N}, where ## N is the number of left cells. ## ## Note that the enumeration ordering we use on cells is not compatible with ## the (reversed) left cell ordering, in the sense that edges in our hasse ## diagram do not always go to elements with a smaller index. It would be ## possible to re-sort the cells so that this would be true, but we have ## refrained from doing that for the sake of consistency. ## positivity_final/headers/GAPlcellwgraphs0000600000175000017500000000145410001256162022204 0ustar duclouxducloux00000000000000## ## This file contains the list of the W-graphs for the various left ## Kazhdan-Lusztig cells in the group. Each cell is sorted w.r.t the shortlex ## normal form order (for the natural ordering of the generators used in GAP, ## unless you have changed that), and the cells are written in the order of ## their first elements. ## ## The file contains the allocation to the variable coxeter_lcwgraphs of a list ## of W-graphs, one for each left cell, which are output as the for the full ## left W-graph of the group, viz. as a list of pairs [descent set, edge list], ## one pair for each node in the cell. The edge-list is again a list of pairs ## [dest,mu], where dest is the destination node of the edge, and mu the ## corresponding mu-coefficient. Nodes are numbered from 1, as is customary ## in GAP. ## positivity_final/headers/GAPcells20000600000175000017500000000175007774163352020725 0ustar duclouxducloux00000000000000## ## The next instruction is the allocation to coxeter_wgraphs of the list of ## the W-graphs of the preceding cells. Each W-graph is printed out as a list ## of pairs, one for each node in the corresponding cell. Each pair is of ## the form [descent set,edge-list] where the descent set is the list of ## descent generators for the corresponding node (in the case of one-sided ## cells) or again a pair [left descent set, right descent set], in the ## case of twosided cells; the edge-list is a list of pairs [dest,mu], where ## mu is the mu-coefficient of the edge, and dest is the destination vertex, ## written here as a single number, viz. its index in the cell for the ## priviously printed enumeration of the cells (recall taht in GAP list ## indices start with 1, not 0.) This is different from the representation of ## W-graphs used in Chevie; Chevie writes down the mu-coefficients as a full ## NxN matrix, where N is the size of the cell, whereas we use a sparse ## representation. ## positivity_final/headers/GAPlwgraph0000600000175000017500000000212310000162125021145 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lwgraph of the ## full left W-graph of the current context. This is guaranteed to be a ## W-graph only when the current context is the full group context; ## otherwise it is the user's responsibility either to ensure that he ## is dealing with a context which is a union of left cells, or to ## get what he can from the partial graph. ## ## In order to be consistent with our other output, we have sorted the ## group elements in shortlex order for the Bourbaki ordering of the ## generators. ## ## For convenience we allocate the enumeration to the variable ## coxeter_contextEnumeration. ## ## The W-graph is represented as a list of pairs [descent set, edge-list], ## one for each element on the context. The descent set is just the list of ## left descents of the element; the edge-list is a list of pairs ## [destination,mu], where mu is the mu-coefficient, and destination is ## the destination of the edge, represented as a number in the enumeration ## of the context that we use (indices start from 1, to be consistent with ## GAP usage.) ## positivity_final/headers/terse_lwgraph0000600000175000017500000000222410000200704022015 0ustar duclouxducloux00000000000000# # The file contains the full left W-graph of the current context. This # contains all the edges of the W-graph which lie in the context; so it # is guaranteed to be a W-graph only when the current context is the full # group; otherwise it is the user's responsibility either to ensure that he # is dealing with a context which is a union of left cells, or to get what # he can from the partial graph. # # The group elements are sorted in shortlex order for the current ordering of # the generators. We start with a list of the shortLex normal forms of the # elements in the context, one per line, sorted in ShortLex order. Then # one line is printed for each element in the context; it starts with the # brace-enclosed descent set of the element, followed by a colon and a # brace-enclosed, comma-separated list of pairs of the form (destination, # mu-coefficient) representing the edges of the graph originating from the # current element; here the destination is just the number of the destination # vertex in the ShortLex numbering that we use (starting from 0.) # # The two lists are separated by a comment line "# graph", in order to # facilitate parsing. # positivity_final/headers/terse_lrcellwgraphs0000600000175000017500000000113110000201356023222 0ustar duclouxducloux00000000000000# # This file contains the list of the W-graphs for the various two-sided # Kazhdan-Lusztig cells in the group. Each cell is sorted w.r.t the shortlex # normal form order (for the ordering of the generators which was current when # this file was created) and the cells are written in the order of their first # elements. # # We print the list of the W-graphs of the various cells, in the usual format # of W-graphs (see the header file for the lwgraph printout). The graphs # are separated by an empty comment line in order to facilitate parsing, # and to make the file more readable for humans. # positivity_final/headers/terse_lcellwgraphs0000600000175000017500000000112410000201262023036 0ustar duclouxducloux00000000000000# # This file contains the list of the W-graphs for the various left # Kazhdan-Lusztig cells in the group. Each cell is sorted w.r.t the shortlex # normal form order (for the ordering of the generators which was current when # this file was created) and the cells are written in the order of their first # elements. # # We print the list of the W-graphs of the various cells, in the usual format # of W-graphs (see the header file for the lwgraph printout). The graphs # are separated by an empty comment line in order to facilitate parsing, # and to make the file more readable for humans. # positivity_final/headers/terse_rcellwgraphs0000600000175000017500000000112510000201334023045 0ustar duclouxducloux00000000000000# # This file contains the list of the W-graphs for the various right # Kazhdan-Lusztig cells in the group. Each cell is sorted w.r.t the shortlex # normal form order (for the ordering of the generators which was current when # this file was created) and the cells are written in the order of their first # elements. # # We print the list of the W-graphs of the various cells, in the usual format # of W-graphs (see the header file for the lwgraph printout). The graphs # are separated by an empty comment line in order to facilitate parsing, # and to make the file more readable for humans. # positivity_final/headers/terse_rcellorder0000600000175000017500000000202407743507002022531 0ustar duclouxducloux00000000000000# # It contains the order relation on the right cells, inherited from the # preorder relation <=_R on the group. What we output is the hasse diagram # of this ordering (or rather of the dual ordering) : for each cell, we # print the list of cells that lie immediately above it (recall that {e} is # the *largest* element in the right cell ordering.) As always, cells are # represented by their index number in the list which is output by lcells; # in this file, we produce the abstract ordering on the integers {0, ..., N-1}, # where N is the number of right cells. # # Note that the enumeration ordering we use on cells is not compatible with # the (reversed) right cell ordering, in the sense that edges in our hasse # diagram do not always go to elements with a smaller index. It would be # possible to re-sort the cells so that this would be true, but we have # refrained from doing that for the sake of consistency. # # We output one edge-list per line, as a comma-separated list; the first line # is an empty list, as it should be! # positivity_final/headers/terse_closure0000600000175000017500000000271610000314565022046 0ustar duclouxducloux00000000000000# # This file contains what is the geometrical data for the schubert cell # corresponding to one element y in the group. It contains the following # information : # # - the element y; # - the extremal pairs for y, output in the form element:polynomial; # - the irreducible components of the rational singular locus; # - the rational singular stratification : this is the set of x for # which P_{x,y} != 1, and which are maximal with that k-l polynomial; # - the ordinary betti numbers; # - the IH betti numbers; # # The various output components are separated by a comment line, to # make the file more readable and to simplify parsing. # # Generators in the group are represented by decimal numbers 1,2, ... ; # the format for outputting group elements as words is the same as for # GAP, viz. prefix "[", separator ",", postfix "]"; so for instance a word # in three generators that would be written as 12321 in our usual "really # terse" style will be written here as [1,2,3,2,1]. # # Polynomials are represented in dense representation, as a list of # coefficients, starting with the coefficient in degree zero. Lists # are comma-separated and enclosed in parentheses. Polynomials may # be preceded by a modifier of the form (d,m); this means that X^d # has to be substituted in the polynomial, and that the result should # be multiplied by X^m; in particular, this is how Laurent polynomials # are obtained. An absent modifier is equivalent to the modifier (1,0). # positivity_final/headers/GAPlrcellwgraphs0000600000175000017500000000160510001256412022362 0ustar duclouxducloux00000000000000## ## This file contains the list of the W-graphs for the various two-sided ## Kazhdan-Lusztig cells in the group. Each cell is sorted w.r.t the shortlex ## normal form order (for the natural ordering of the generators used in GAP, ## unless you have changed that), and the cells are written in the order of ## their first elements. ## ## The file contains the allocation to the variable coxeter_lrcwgraphs of a ## list of W-graphs, one for each two-sided cell, which are output as the for ## the full two-sided W-graph of the group, viz. as a list of pairs ## [descent set, edge list], one pair for each node in the cell. The descent ## set is a pair [right descent set, left descent set]; the edge-list is again ## a list of pairs [dest,mu], where dest is the destination node of the edge, ## and mu the corresponding mu-coefficient. Nodes are numbered from 1, as is ## customary in GAP. ## positivity_final/headers/GAPrwgraph0000600000175000017500000000212610000162217021160 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_rwgraph of the ## full right W-graph of the current context. This is guaranteed to be a ## W-graph only when the current context is the full group context; ## otherwise it is the user's responsibility either to ensure that he ## is dealing with a context which is a union of right cells, or to ## get what he can from the partial graph. ## ## In order to be consistent with our other output, we have sorted the ## group elements in shortlex order for the Bourbaki ordering of the ## generators. ## ## For convenience we allocate the enumeration to the variable ## coxeter_contextEnumeration. ## ## The W-graph is represented as a list of pairs [descent set, edge-list], ## one for each element on the context. The descent set is just the list of ## right descents of the element; the edge-list is a list of pairs ## [destination,mu], where mu is the mu-coefficient, and destination is ## the destination of the edge, represented as a number in the enumeration ## of the context that we use (indices start from 1, to be consistent with ## GAP usage.) ## positivity_final/headers/terse_lrcellorder0000600000175000017500000000204507743506762022724 0ustar duclouxducloux00000000000000# # It contains the order relation on the two-sided cells, inherited from the # preorder relation <=_LR on the group. What we output is the hasse diagram # of this ordering (or rather of the dual ordering) : for each cell, we # print the list of cells that lie immediately above it (recall that {e} is # the *largest* element in the two-sided cell ordering.) As always, cells are # represented by their index number in the list which is output by lcells; # in this file, we produce the abstract ordering on the integers {0, ..., N-1}, # where N is the number of two-sided cells. # # Note that the enumeration ordering we use on cells is not compatible with # the (reversed) two-sided cell ordering, in the sense that edges in our hasse # diagram do not always go to elements with a smaller index. It would be # possible to re-sort the cells so that this would be true, but we have # refrained from doing that for the sake of consistency. # # We output one edge-list per line, as a comma-separated list; the first line # is an empty list, as it should be! # positivity_final/headers/GAPrcellorder0000600000175000017500000000174207743517267021703 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lcellOrder of the ## order relation on the right cells, inherited from the preorder relation ## <=_R on the group. What we output is the hasse diagram of this ordering ## (or rather of the dual ordering) : for each cell, we print the list ## of cells that lie immediately above it (recall that {e} is the *largest* ## element in the right cell ordering.) As always, cells are represented ## by their index number in the list which is output by lcells; in this ## file, we produce the abstract ordering on the integers {1, ..., N}, where ## N is the number of right cells. ## ## Note that the enumeration ordering we use on cells is not compatible with ## the (reversed) right cell ordering, in the sense that edges in our hasse ## diagram do not always go to elements with a smaller index. It would be ## possible to re-sort the cells so that this would be true, but we have ## refrained from doing that for the sake of consistency. ## positivity_final/headers/GAPrcellwgraphs0000600000175000017500000000146210001256477022222 0ustar duclouxducloux00000000000000## ## This file contains the list of the W-graphs for the various right ## Kazhdan-Lusztig cells in the group. Each cell is sorted w.r.t the shortlex ## normal form order (for the natural ordering of the generators used in GAP, ## unless you have changed that), and the cells are written in the order of ## their first elements. ## ## The file contains the allocation to the variable coxeter_rcwgraphs of a list ## of W-graphs, one for each right cell, which are output as the for the full ## right W-graph of the group, viz. as a list of pairs [descent set, ## edge list], one pair for each node in the cell. The edge-list is again a ## list of pairs [dest,mu], where dest is the destination node of the edge, ## and mu the corresponding mu-coefficient. Nodes are numbered from 1, as is ## customary in GAP. ## positivity_final/headers/terse_slocus0000600000175000017500000000207610001231334021672 0ustar duclouxducloux00000000000000# # This file contains the printout of the maximal elements in the set of # x < y s.t. P_{x,y} != 1. In the case where W is crystallographic, these # correspond to the irreducible components of the rational singular locus # of the Schubert variety X_y. # # Generators in the group are represented by decimal numbers 1,2, ... ; # the format for outputting group elements as words is the same as for # GAP, viz. prefix "[", separator ",", postfix "]"; so for instance a word # in three generators that would be written as 12321 in our usual "really # terse" style will be written here as [1,2,3,2,1]. # # Polynomials are represented in dense representation, as a list of # coefficients, starting with the coefficient in degree zero. Lists # are comma-separated and enclosed in parentheses. Polynomials may # be preceded by a modifier of the form (d,m); this means that X^d # has to be substituted in the polynomial, and that the result should # be multiplied by X^m; in particular, this is how Laurent polynomials # are obtained. An absent modifier is equivalent to the modifier (1,0). # positivity_final/headers/GAPlrcellorder0000600000175000017500000000176307743517357022062 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lcellOrder of the ## order relation on the tow-sided cells, inherited from the preorder relation ## <=_LR on the group. What we output is the hasse diagram of this ordering ## (or rather of the dual ordering) : for each cell, we print the list ## of cells that lie immediately above it (recall that {e} is the *largest* ## element in the two-sided cell ordering.) As always, cells are represented ## by their index number in the list which is output by lcells; in this ## file, we produce the abstract ordering on the integers {1, ..., N}, where ## N is the number of two-sided cells. ## ## Note that the enumeration ordering we use on cells is not compatible with ## the (reversed) two-sided cell ordering, in the sense that edges in our hasse ## diagram do not always go to elements with a smaller index. It would be ## possible to re-sort the cells so that this would be true, but we have ## refrained from doing that for the sake of consistency. ## positivity_final/headers/GAPclosure0000600000175000017500000000217210000523242021162 0ustar duclouxducloux00000000000000## ## All group elements are represented by their shortlex normal forms in ## the GAP conventions (unless you did something to change that). ## ## This file contains what is the geometrical data for the schubert cell ## corresponding to one element y in the group. It contains the following ## allocations : ## ## coxeter_currentElement : the element y; ## coxeter_criticalPairs : the list of all x s.t. (x,y) is a critical ## pair, together with the corresponding k-l polynomial (as a polynomial ## in q = u^2); ## coxeter_slocus : the (rational) singular locus, a sublist of ## coxeter_criticalPairs; ## coxeter_sstratification : for each polynomial P != 1 which occurs ## among the P_{x,y}, we look a the x s.t. P_{x,y} = P and which are ## maximal in the Bruhat ordering; this is another sublist of ## coxeter_criticalPairs; ## coxeter_betti : the ordinary betti numbers; ## coxeter_ihbetti : the intersection homology betti numbers; ## ## Look at the header files and/or help functions for the commands extremals, ## slocus, sstratification, betti and ihbetti for more details on these ## concepts. ## positivity_final/headers/GAPslocus0000600000175000017500000000047110001232462021020 0ustar duclouxducloux00000000000000## ## This file contains the allocation to the variable coxeter_slocus of ## a list of pairs [elt,pol], where elt runs through the maximal elements ## of the set of x < y s.t. P_{x,y} != 1. When W is crystallographic, ## these are the components of the rational singular locus of the Schubert ## variety X_y. ## positivity_final/headers/terse_rwgraph0000600000175000017500000000222610000201021022016 0ustar duclouxducloux00000000000000# # The file contains the full right W-graph of the current context. This # contains all the edges of the W-graph which lie in the context; so it # is guaranteed to be a W-graph only when the current context is the full # group; otherwise it is the user's responsibility either to ensure that he # is dealing with a context which is a union of right cells, or to get what # he can from the partial graph. # # The group elements are sorted in shortlex order for the current ordering of # the generators. We start with a list of the shortLex normal forms of the # elements in the context, one per line, sorted in ShortLex order. Then # one line is printed for each element in the context; it starts with the # brace-enclosed descent set of the element, followed by a colon and a # brace-enclosed, comma-separated list of pairs of the form (destination, # mu-coefficient) representing the edges of the graph originating from the # current element; here the destination is just the number of the destination # vertex in the ShortLex numbering that we use (starting from 0.) # # The two lists are separated by a comment line "# graph", in order to # facilitate parsing. # positivity_final/headers/terse_lrwgraph0000600000175000017500000000232410000241231022200 0ustar duclouxducloux00000000000000# # The file contains the full two-sidedW-graph of the current context. This # contains all the edges of the W-graph which lie in the context; so it # is guaranteed to be a W-graph only when the current context is the full # group; otherwise it is the user's responsibility either to ensure that he # is dealing with a context which is a union of two-sided cells, or to get # what he can from the partial graph. # # The group elements are sorted in shortlex order for the current ordering of # the generators. We start with a list of the shortLex normal forms of the # elements in the context, one per line, sorted in ShortLex order. Then # one line is printed for each element in the context; it starts with the # brace-enclosed descent set of the element, written in the form # {left descents;right descents}, followed by a colon and a brace-enclosed, # comma-separated list of pairs of the form (destination, mu-coefficient), # representing the edges of the graph originating from the current element; # here the destination is just the number of the destination vertex in the # ShortLex numbering that we use (starting from 0.) # # The two lists are separated by a comment line "# graph", in order to # facilitate parsing. # positivity_final/headers/terse_lcells0000600000175000017500000000077607777275767021721 0ustar duclouxducloux00000000000000# # The file contains the list of the various left Kazhdan-Lusztig cells in # the group. Each cell is sorted w.r.t the shortlex normal form order (for # the ordering of the generators which was current when this file was created) # and the cells are written in the order of their first elements. All the # printouts relating to left cells, such as Duflo involutions and left cell # order, are consistent with this enumeration of the cells. # # Left cells (one cell per line, as a comma-separated list) : # positivity_final/headers/terse_sstratification0000600000175000017500000000252510001232001023557 0ustar duclouxducloux00000000000000# # For each polynomial P != 1 which occurs among the P_{x,y}, x < y, we # print out the maximal elements in the set of x < y s.t. P_{x,y} = P, # together with the corresponding k-l polynomial. In the case where # W is crystallographic, these are the irreducible components of the # the "rational singular stratification" of the Schubert variety X_y, # where P_{x,y} is used as a measure of the severity of the singularity # along the subvariety defined by x. It is known that in this case, # P_{x,y} is a decreasing function of x. # # Generators in the group are represented by decimal numbers 1,2, ... ; # the format for outputting group elements as words is the same as for # GAP, viz. prefix "[", separator ",", postfix "]"; so for instance a word # in three generators that would be written as 12321 in our usual "really # terse" style will be written here as [1,2,3,2,1]. # # Polynomials are represented in dense representation, as a list of # coefficients, starting with the coefficient in degree zero. Lists # are comma-separated and enclosed in parentheses. Polynomials may # be preceded by a modifier of the form (d,m); this means that X^d # has to be substituted in the polynomial, and that the result should # be multiplied by X^m; in particular, this is how Laurent polynomials # are obtained. An absent modifier is equivalent to the modifier (1,0). # positivity_final/headers/terse_lrcells0000600000175000017500000000077707777250633022065 0ustar duclouxducloux00000000000000# # The file contains the list of the various two-sided Kazhdan-Lusztig cells # in the group. Each cell is sorted w.r.t the shortlex normal form order # (for the ordering of the generators which was current when this file was # created) and the cells are written in the order of their first elements. # All the printouts relating to two-sided cells, such as two-sided cell # ordering, are consistent with this enumeration of the cells. # # Two-sided cells (one cell per line, as a comma-separated list) : # positivity_final/headers/terse_rcells0000600000175000017500000000100207777250670021670 0ustar duclouxducloux00000000000000# # The file contains the list of the various right Kazhdan-Lusztig cells in # the group. Each cell is sorted w.r.t the shortlex normal form order (for # the ordering of the generators which was current when this file was created) # and the cells are written in the order of their first elements. All the # printouts relating to right cells, such as Duflo involutions and right # cell order, are consistent with this enumeration of the cells. # # Right cells (one cell per line, as a comma-separated list) : # positivity_final/headers/terse_lcorder0000600000175000017500000000202010000212542022000 0ustar duclouxducloux00000000000000# # It contains the order relation on the left cells, inherited from the # preorder relation <=_L on the group. What we output is the hasse diagram # of this ordering (or rather of the dual ordering) : for each cell, we # print the list of cells that lie immediately above it (recall that {e} is # the *largest* element in the left cell ordering.) As always, cells are # represented by their index number in the list which is output by lcells; # in this file, we produce the abstract ordering on the integers {0, ..., N-1}, # where N is the number of left cells. # # Note that the enumeration ordering we use on cells is not compatible with # the (reversed) left cell ordering, in the sense that edges in our hasse # diagram do not always go to elements with a smaller index. It would be # possible to re-sort the cells so that this would be true, but we have # refrained from doing that for the sake of consistency. # # We output one edge-list per line, as a comma-separated list; the first line # is an empty list, as it should be! # positivity_final/headers/GAPlcells0000600000175000017500000000075007777300050021005 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lcells of the list ## of all left Kazhdan-Lusztig cells in the group. Each cell is sorted ## w.r.t the shortlex normal form order (for the natural ordering of the ## generators used in GAP, unless you have changed that), and the cells ## are written in the order of their first elements. All the printouts ## relating to left cells, such as Duflo involutions and left cell order, ## are consistent with this choice of ordering. ## positivity_final/headers/GAPlrcells0000600000175000017500000000073607777251053021203 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_lrcells of the list ## of all two-sided Kazhdan-Lusztig cells in the group. Each cell is sorted ## w.r.t the shortlex normal form order (for the natural ordering of the ## generators used in GAP, unless you have changed that), and the cells ## are written in the order of their first elements. All the printouts ## relating to two-sided cells, two-sided cell ordering, are consistent with ## this choice of ordering. ## positivity_final/headers/GAPrcells0000600000175000017500000000075307777251032021023 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_rcells of the list ## of all right Kazhdan-Lusztig cells in the group. Each cell is sorted ## w.r.t the shortlex normal form order (for the natural ordering of the ## generators used in GAP, unless you have changed that), and the cells ## are written in the order of their first elements. All the printouts ## relating to right cells, such as Duflo involutions and right cell order, ## are consistent with this choice of ordering. ## positivity_final/headers/GAPsstratification0000600000175000017500000000127510001232771022724 0ustar duclouxducloux00000000000000## ## This file contains the allocation to the variable coxeter_sstratification ## of the list of pairs [elt,pol], where elt runs through the maximal ## elements of the sets of x < y with a given k-l polynomial != 1; pol is ## the correswponding k-l polynomial. In the case where W is crystallographic, ## these are the irreducible components of the the "rational singular ## stratification" of the Schubert variety X_y, where P_{x,y} is used as a ## measure of the severity of the singularity along the subvariety defined by ## x. It is known that in this case, P_{x,y} is a decreasing function of x. ## ## NOTE : the ordering of the printout is inverse to the one used in Goresky's ## files. ## positivity_final/headers/GAPrcorder0000600000175000017500000000173710000214271021153 0ustar duclouxducloux00000000000000## ## It contains the allocation to the variable coxeter_rcorder of the ## order relation on the right cells, inherited from the preorder relation ## <=_R on the group. What we output is the hasse diagram of this ordering ## (or rather of the dual ordering) : for each cell, we print the list ## of cells that lie immediately above it (recall that {e} is the *largest* ## element in the right cell ordering.) As always, cells are represented ## by their index number in the list which is output by lcells; in this ## file, we produce the abstract ordering on the integers {1, ..., N}, where ## N is the number of right cells. ## ## Note that the enumeration ordering we use on cells is not compatible with ## the (reversed) right cell ordering, in the sense that edges in our hasse ## diagram do not always go to elements with a smaller index. It would be ## possible to re-sort the cells so that this would be true, but we have ## refrained from doing that for the sake of consistency. ## positivity_final/headers/terse_lrcorder0000600000175000017500000000204510000214041022165 0ustar duclouxducloux00000000000000# # It contains the order relation on the two-sided cells, inherited from the # preorder relation <=_LR on the group. What we output is the hasse diagram # of this ordering (or rather of the dual ordering) : for each cell, we # print the list of cells that lie immediately above it (recall that {e} is # the *largest* element in the two-sided cell ordering.) As always, cells are # represented by their index number in the list which is output by lcells; # in this file, we produce the abstract ordering on the integers {0, ..., N-1}, # where N is the number of two-sided cells. # # Note that the enumeration ordering we use on cells is not compatible with # the (reversed) two-sided cell ordering, in the sense that edges in our hasse # diagram do not always go to elements with a smaller index. It would be # possible to re-sort the cells so that this would be true, but we have # refrained from doing that for the sake of consistency. # # We output one edge-list per line, as a comma-separated list; the first line # is an empty list, as it should be! # positivity_final/headers/terse_rcorder0000600000175000017500000000202410000214101022003 0ustar duclouxducloux00000000000000# # It contains the order relation on the right cells, inherited from the # preorder relation <=_R on the group. What we output is the hasse diagram # of this ordering (or rather of the dual ordering) : for each cell, we # print the list of cells that lie immediately above it (recall that {e} is # the *largest* element in the right cell ordering.) As always, cells are # represented by their index number in the list which is output by lcells; # in this file, we produce the abstract ordering on the integers {0, ..., N-1}, # where N is the number of right cells. # # Note that the enumeration ordering we use on cells is not compatible with # the (reversed) right cell ordering, in the sense that edges in our hasse # diagram do not always go to elements with a smaller index. It would be # possible to re-sort the cells so that this would be true, but we have # refrained from doing that for the sake of consistency. # # We output one edge-list per line, as a comma-separated list; the first line # is an empty list, as it should be! # positivity_final/README0000600000175000017500000000215010256226304016510 0ustar duclouxducloux00000000000000 Copyright (C) 2005 Fokko du Cloux This is the README file for the special version of Coxeter 3.0 which verifies the non-negativity of the structure constants of the Hecke algebra in the Kazhdan-Lusztig basis. The main thrust is to do this verification in type H4 (although it is interesting as well to look at the shape of these coefficients for other finite groups where they are already known to be non-negative.) You should refer to my note "Some positivity properties for the Hecke algebra in type H4" for an explanation of what the program does, and what commands are available (this is currently being submitted, and may be found on my website.) To compile the program, simply say "make" in this directory. You will obtain an executable named "coxeter". To do the actual positivity check, you can either enter the program and type "positivity", or, if you are interested in type H4, execute the little "coxbatch" script that I have included. You should expect a running time of about 80 hours on a decent server, and a memory requirement of not more than 2GB on a 64-bit machine, and around 1 GB on a 32-bit machine. positivity_final/INTRO.tex0000600000175000017500000013116607775760226017301 0ustar duclouxducloux00000000000000\documentclass[11pt]{article} \addtolength{\textwidth}{2cm} \addtolength{\hoffset}{-1cm} \makeatletter \renewcommand{\subsection}[1]{\@startsection{subsection}{2}{0pt}% {\medskipamount}{-4.5 pt}{\textbf}{#1}\hskip-\parindent\textbf{. }} \makeatother \usepackage{url} \newcommand{\coxeter}{{\tt Coxeter}} \renewcommand{\a}{\alpha} \renewcommand{\b}{\beta} \newcommand{\ds}{\displaystyle} \newcommand{\GAP}{{\tt GAP}} \renewcommand{\iff}{if and only if} \newcommand{\kl}{Kazh\-dan--Lusz\-tig} \newcommand{\klpol}{Kazh\-dan--Lusz\-tig po\-ly\-no\-mial} \newcommand{\LR}{{\rm LR}} \renewcommand{\min}{_{\rm min}} \newcommand{\Rc}{{\cal R}} \newcommand{\Sc}{{\cal S}} \begin{document} \title{Coxeter version 3.0} \author{Fokko du Cloux} \maketitle \begin{flushleft} Institut Girard Desargues\\ UMR 5028 CNRS\\ Universit\'e Lyon-I\\ 69622 Villeurbanne Cedex FRANCE\\ {\tt ducloux@igd.univ-lyon1.fr} \end{flushleft} \noindent\coxeter\ is a program for the exploration of combinatorial issues related to Coxeter groups and Hecke algebras, with a particular emphasis on the computation of \klpol s and related questions. It is not a symbolic algebra system; rather, it is an interface for accessing a direct C++ implementation of the concept of a Coxeter group. Although I have not been able to fully reach this goal in the current version, the idea is to make the class (actually, the class hierarchy) of Coxeter groups available in the form of a C++ library, which could then be used efficiently by other programmers. The program aims for maximum performance, both in terms of speed and in terms of memory usage; it does not aim for maximal user-friendliness. If your needs are served by higher-level programs like {\tt GAP/Chevie} or {\tt Maple}, by all means use those; the aim of \coxeter\ is to pick up where these programs stop. Particularly {\tt Chevie} includes a nice set of \kl\ routines, including some which are not implemented in \coxeter. Extending the program is certainly possible (see below), but only for users who are on speaking terms with C++ and are willing to walk a little through the {\tt .h} files. Extension takes place by inserting your own additional code, typically in the {\tt special.cpp} file, and recompiling (unless you are adding whole new files, recompiling should just be typing {\tt make}.) \section{What is wrong with this program}\label{section:wrong} What is mostly wrong with this program is that is neither C nor C++. In fact, this program has been my learning ground for C++ (where I used to be a C programmer). I made the shift with some reluctance, as I tend to love the simple-minded no-nonsense approach of C, and particularly the blazing efficiency that you can get out of it. When I finally decided to make the switch, a sizable amount of C code had already been written; moreover I couldn't afford to take the time to learn everything I should have about C++ for such a project. Therefore, although largely C++ in spirit, the program suffers from a number of severe defects and shortcomings from the C++ standpoint~: \begin{itemize}\itemsep0 pt \item[$\bullet$]i/o is not C++ at all; it is plain C. \item[$\bullet$]I didn't make use of the STL, even though the program makes heavy use of things that are provided by the STL, and which I had reinvented before even realizing that the STL existed : my class {\tt List} is essentially STL's {\tt vector}, where I use binary trees I could have used STL's {\tt set} class, of course I should have used STL's {\tt string}, etc. \item[$\bullet$]I'm not using exceptions at all; instead I've implemented my own error handling mechanism, probably not rigorously enough. Badly handled error conditions have been the main source of program crashes in my testing. \end{itemize} \noindent Memory allocation is another thorny issue. Whether this was due to clumsy programming on my part, or to the overhead of the default memory allocator, when I tried to use the builtin {\tt new}, in presence of heavy resizing (which happens often in large computations) performance all of a sudden became terrible (and I mean terrible~: slowing down by a factor of at least ten, maybe more.) Therefore I decided to write my own primitive allocator, getting only fairly large (never smaller than $2^{16}$ bytes by default) blocks from the system, and never returning them during the lifetime of the program. My allocations always are a power of $2$ bytes, and therefore as much as 50\%\ of the memory might get wasted (although the ratio in practice is much better), but at least the speed is satisfactory. At that time I hadn't heard yet about the possibility of specifying a memory allocator for the STL classes; in any case I will make the switch to STL classes only if this issue is resolved. \section{What the program does}\label{section:does} One of the main improvements with respect to previous versions of \coxeter\ is that the program is now able to handle essentially arbitrary Coxeter groups (provided of course that the computation you require does not overflow your system). For convenience, and also because it seems to cover all cases where significant computations are possible, in this version I require that twice the rank of the group not exceed the number of bits in a {\tt long} on your system (so the rank is limited to $16$ on a $32$-bit machine, and to $32$ on a $64$-bit machine.) One could argue that $16$ is a bit restrictive, but certainly $32$ will cover all cases of interest. \medskip \noindent The functionalities provided by the program may be classified in a number of categories~: \smallskip \noindent{\em elementary operations~:} reduced form computations; products; descent sets; elementary Bruhat order comparison; coatoms. %\smallskip %\noindent{\em Bruhat ordering~:} Bruhat intervals; extremal pairs; \smallskip \noindent{\em\klpol s~:} individual \klpol s and mu-coef\-fi\-cients for the ordinary, unequal-parameter and inverse cases; layout of a polynomial computation in these cases; \kl\ basis elements in the Hecke algebra; singular stratification, rational singular locus, ordinary and IH Betti numbers of a Schubert variety. \smallskip \noindent{\em\kl\ cells~:} left, right and two-sided cells for the ordinary and unequal-parameter cases; ordering on the cells of a finite Coxeter group in both these cases. \medskip \noindent One of the serious issues that have to be faced in computational mathematics is the sheer size of the output for the computations that modern-day computers are able to handle. Dumping the output on a screen is definitely not good enough in many cases. I have no real solution for this problem; in any case it is clear that more and more output will be handled electronically, and will have to be analyzed by other programs before being usable by humans. I offer a number of output formats for output to files : a human-readable one, a ``terse'' one which is designed to be easily computer-readable, for analysis or further processing, and \GAP-format. The latter is a first step towards connecting (some appropriate version of) \coxeter\ with \GAP. \section{What is missing from this version}\label{section:missing} A number of things that I would have liked to put in the program are missing. Foremost are parabolic \klpol s. They are important in their own right, but also because the parabolic setting comes much closer to capture the real difficulty of a \kl\ computation. Some computations, say of parabolic \klpol s in type $E_8$, will not go through in this version even though they are actually rather small, only because as a preliminary the program tries to construct an enormous Bruhat interval. If we handled things in a parabolic setting, the parabolic interval would be constructed instead, which would not be a problem. This would certainly be my number one project (apart from improving the code structure) for a future version. Also, there is nowhere as much stuff on Bruhat intervals as I would like to have. A {\em lot} more can be said, asked, and done about them. But perhaps this really would require a different program. It may not be a good idea trying to do everything in one place. There is no attempt to handle special groups in any special way. The only way in which finite groups are special in this program is through the fact that some computations, such as \kl\ cell computations for instance, are defined only for them. It is likely that Bruhat order computations could be much improved for finite groups; still, my measurements seem to show that even in the current state, Bruhat order computations are not all that dominant, so that at most one could expect to gain a factor of two (and usually much less). In view of the speed already attained, this doesn't seem worth the effort. Users who are especially interested in type $A$ should check out Gregory Warrington's programs (see \url{http://www.math.upenn.edu/~gwar/research/research.html}) \section{How to extend the program}\label{section:extend} The usual mechanism used by computer algebra programs to extend the capabilities of the program beyond the predefined commands is to provide an interpreted programming language that allows the user to write his own routines. No such thing is provided here. However, there is a command called {\tt special}, defined in {\tt special.cpp}, which executes the {\tt special\_f} function defined in that file. Currently this function just prints out a short warning message, but it can be redefined by inserting any code you wish (and then recompiling the program of course.) It is also easy to insert new command names executing user-defined functions; it should be easy to guess what needs to be done by looking at the way the {\tt special} command is defined in {\tt special.cpp}. Of course this is only useful for users which are knowledgeable with C++. Also, to do anything useful, you will want to use the functionalities already provided by the {\tt CoxGroup} class; this will require reading a few of the {\tt .h} files to see what is available. In fact, I have tried to make the most useful commands available already at the level of the {\tt CoxGroup} class (or sometimes in the derived class {\tt FiniteCoxGroup} if the command doesn't make sense for a general Coxeter group.) So in principle it would be enough to look there; however, most of the functions from {\tt CoxGroup} are simply forwarded from the various components of the class, so it will be necessary to look at a number of other files to see the definitions and comments for all these functions. \section{How things are done: word reduction}\label{section:reduction} The following sections describe in some more detail the algorithms that are used in the program to perform the computations. We begin with the most fundamental one, which is word reduction. What I have done is provide a complete, purely combinatorial implementation of the minimal root algorithm discovered by Brigitte Brink and Bob Howlett \cite{brink_howlett:1993}; the usage of minimal roots for word reduction and normalization, and the practical aspects of the construction of the set of minimal roots, are nicely discussed in \cite{casselman:2002}. For any Coxeter system $(W,S)$, Brink and Howlett define a canonical finite subset $E$ of the set of positive roots of $W$, called the set of minimal (or elementary) roots, which contains the simple roots. Define an action of $S$ on the set $X=E\cup\{+,-\}$, where $+$ and $-$ are two special symbols, by letting $+$ and $-$ be fixed points, and setting $s.\a=+$ if $\a$ is a positive root not in $E$, $s.\a=-$ if $\a=\a_s$ is the simple root corresponding to $s$, and $s.\a=\b\in E$ otherwise. So we can now view $X$ as a finite state automaton with alphabet $S$ (except that we do not choose an initial state or a set of accept states at this point.) Then it is shown in \cite{brink_howlett:1993} that if $s_1\ldots s_p$ is a {\em reduced} word in $W$, and if we read this word through the automaton, starting from the state $\a_s$, the word $s_1\ldots s_ps$ is reduced, unless we reach the state $-$; moreover, if the generator $s_j$ takes us from state $\a_t$ to state $-$, we have $s_j=t$ and $s_{j+1}\ldots s_ps=ts_{j+1}\ldots s_p$; hence the reduction. It is clear now how the above automaton can be used to reduce an arbitrary word in the generators, in at most quadratic time. This algorithm is implemented in the function {\tt MinTable::prod} in {\tt minroots.cpp}. Of course it remains to construct the set of minimal roots, together with the action of the generators above. In \cite{brink_howlett:1993} an algorithm is described in terms of the standard geometrical realization of the group. This algorithm has the drawback that it requires finding the sign of potentially complicated algebraic real numbers. Using the detailed analysis of minimal roots in \cite{brink:1998}, it is possible to make the algorithm entirely combinatorial, using only a few explicit irrationalities (and even then, in a formal fashion.) This is explained in more detail at the beginning of {\tt minroots.cpp}. The upshot is that we are able to construct the ``minimal root machine'' for essentially any Coxeter group. The only possible source of trouble is memory overflow; even though for the most frequently used Coxeter groups (such as finite or affine groups) the number of minimal roots is fairly small (typically a few hundred), it can grow larger for more exotic cases. For ranks $\leq 16$, if the entries of the Coxeter matrix are not too large, there should not be more than a few tens of thousands of roots; but for ranks $\leq 32$, millions of minimal roots should be expected in bad cases. The program will quit if it is unable to construct the minimal root table; nothing useful can be done without word reduction. Another problem that is neatly solved with the minimal root machine is the {\em word problem} for Coxeter groups~: recognizing when two words in the generators represent the same element. If $s_1\ldots s_p$ is a reduced word in the generators, and $s$ is a generator such that $s_1\ldots s_ps$ is reduced, it turns out that the procedure described above also finds all possible ways to insert a generator $t$ in $s_1\ldots s_p$, say after the $j$-th letter, so that $s_1\ldots s_jts_{j+1}\ldots s_p=s_1\ldots s_ps$. Define the normal form of an element $w\in W$ to be the lexicographically smallest reduced expression of $w$ (with respect to a chosen linear ordering on the set $S$). Then it is known that if $s_1\ldots s_p$ is a normal form, and $s_1\ldots s_ps$ is reduced (not reduced), the normal form of $s_1\ldots s_ps$ is obtained through a suitable insertion (deletion) in $s_1\ldots s_p$. Now it is easy to show that the minimal root machine in fact will find all possible insertion/deletion places in a given word, for the multiplication by an additional generator $s$; so it is also possible to construct the normal form of an element using the finite state automaton described above. Of course, once we have word reduction it is an easy matter to determine (though not very efficiently) the descent set of any given element of the group (recall that the left (right) descent set of $w\in W$ is the set of $s\in S$ such that $l(sw)1$. If $x$ is not extremal w.r.t. $y$, we also know that $\mu(x,y)=0$; so we may also assume that $x$ is ectremal w.r.t. $y$. These easy reductions, by the way, determine the default allocation of a row in the $\mu$-table~: when no further reductions are available, we allocate one entry for each $x$ satisfying the above conditions. Now look at the recursion formula for $\mu(x,y)$ obtained by taking the term of degree $\ds{\frac{1}{2}(l(y)-l(x)-1)}$ in the recursion formula for $P_{x,y}$. We start with $\mu(xs,ys)$, then add the coefficient in degree $\ds{\frac{1}{2}(l(ys)-l(x)-2)}$ in $P_{x,ys}$ (note that the length difference between $x$ and $ys$ is even, so this is the highest-possible degree term in $P_{x,ys}$, but not a $\mu$-coefficient), and subtract the sum of all $\mu(x,z)\mu(z,ys)$, where $xx$ (following our usual conventions we write products on the right, but when $t>n$ this is in fact multiplication on the left), in other words, if $x$ is not also extremal w.r.t. $ys$, then we see that the term we need from $P_{x,ys}$ is in fact $\mu(xt,ys)$, and the recursion takes place entirely within the $\mu$-table. But much more is true~: following \cite{kl:1979}, section 4, one sees that in the subtracted sum there are at most two non-vanishing terms. Indeed, if $l(ys)-l(z)=1$, then we will have $ztz$ unless $z=xt$; and if $zt>z$, $z$ is not extremal w.r.t.\ $ys$. And if both length differences are $>1$, we have $\mu(x,z)=0$ if $ztz$. Since $\mu$-coefficients are $1$ when the length difference is one, we see that the subtracted sum reduces at most to the two terms $\mu(x,yst)+\mu(xt,ys)$. The additional condition $zsyst$\cr \mu(xs,ys)-\mu(x,yst)&if $xtsxt$, $ysts>yst$\cr \mu(xs,ys)+\mu(xt,ys)-\mu(x,yst)&if $xts>xt$, $ystsx$ implies $yt>y$; but it is easy to see that $ystxt$ we have $xsxs$, hence $xs$ is not extremal w.r.t.\ $ys$, and $\mu(xs,ys)=0$. So the formul\ae\ simplify to~: $$ \mu(x,y)=\cases{\mu(xs,ys)&if $xtsxt$\cr} $$ The upshot is that the full recursion formula involving the extraction of the interval $[x,ys]$ has to be called only if $\LR(x)$ contains not only $\LR(y)$, but $\LR(ys)$ as well for {\em every} $s\in\LR(y)$. This will happen only in a very small number of cases. On the other hand, when it does happen, the computation of $\mu(x,y)$ will trigger a great many recursive calls, so that in the end the gain is not as big as one might expect at first. Another aspect of things is that one might use these remarks to condense the $\mu$-table considerably, storing only the ``double-extremal'' pairs, particularly in the case of simply-laced groups. This would certainly be the way to go if one were to attempt the computation of, say, the full $W$-graph of a group like ${\rm E}_7$. I plan to explore these issues further using a suitably modified version of the program. \section{How things are done: \kl\ cells}\label{section:klcells} Another feature missing from \coxeter1 which is provided by \coxeter3 is the computation of (left, right and two-sided) \kl\ cells. This is done only for finite groups, as I don't see as yet a rigorous way of doing it for infinite groups even when, as in the case of affine groups, it is known that the set of cells is finite. One brute-force way of computing cells is to compute the full $\mu$-table of the group, get from there the full $W$-graph, and then notice that the problem is an instance of a classic computer algebra problem, {\em viz.} computing equivalence classes in an oriented graph. (I wish to thank Bill Casselman for pointing this out, and for explaining to me the Tarjan algorithm which performs this computation.) In fact, if in addition to the partition of the group in cells, one wishes to recover the poset structure on the set of cells (which for finite Weyl groups is isomorphic to the poset of primitive ideals in the enveloping algebra of the corresponding semisimple Lie algebra, with trivial infinitesimal character), then it is not very likely that one can get away with much less than that. But if only the partition is required, much less needs to be done. Here is how one might go about it. We will say that two elements $x$ and $y$ in $W$ are in the same right descent class, if their right descent sets are equal. It is known already from \cite{kl:1979} that all elements of a given left cell are in the same right descent class. Moreover, there is a set of partially defined operations on the group, the so-called $*$-operations, which preserve left cells. One operation is defined for each pair of non-commuting elements $s,t$ in the group. The idea is to look at the right cosets for the parabolic subgroup generated by $s$ and $t$. If we set $m=m(s,t)$, then each coset has $2m$ elements, one of minimal length, one of maximal length, and two in each intermediate lengths. The domain of the operation $*_{s,t}$ is the set of elements in $W$ which are neither of minimal nor of maximal length in their coset (equivalently, this means that $R(w)\cap\{s,t\}$ has exactly one element.) For each coset $C$ in $W$ with minimal length representative $x\min$ we define the two $\{s,t\}$-chains of $C$ to be the $(m-1)$-element sets $C_s=\{x\min s,x\min st,\ldots\}$ and $C_t=\{x\min t,x\min ts,\ldots\}$. Then each element $w$ in the domain of $*_{s,t}$ is contained in exactly one $\{s,t\}$-chain $\{x_1,\ldots,x_{m-1}\}$. If $j\in\{1,\ldots,m-1\}$ is the index such that $w=x_j$, we set $w*_{s,t}=x_{m-j}$. In particular, $*_{s,t}$ permutes each $\{s,t\}$-chain. Clearly the domain of each $*_{s,t}$ is a union of right descent classes, and therefore of left cells. Then it is known \cite{lusztig:1985} that $*_{s,t}$ takes each left cell in its domain to another left cell. This allows us to refine the partition of $W$ in right descent classes as follows. We define a sequence of partitions $(\Rc_k)_{k\geq 1}$ of $W$ by letting $\Rc_1$ be the partition in right descent classes, and saying that $x$ and $y$ have same class in $\Rc_k$, $k>1$, \iff\ they belong to the same class in $\Rc_{k-1}$, and for each pair $\{s,t\}$ of non-commuting generators in the group such that $*_{s,t}$ is defined for $x$ (and hence for $y$), $x*_{s,t}$ and $y*_{s,t}$ also belong to the same class in $\Rc_{k-1}$. We then define $\Rc_\infty$ by saying that $x$ and $y$ belong to the same class in $\Rc_\infty$ \iff\ they belong to the same class in $\Rc_k$ for all $k\geq1$. Clearly the partition of $W$ in left cells refines the partition $\Rc_\infty$; in the case of a finite Weyl group, the partition $\Rc_\infty$ is the generalized $\tau$-partition introduced by David Vogan \cite{vogan:1979}. It turns out that it is not hard to compute the partition $\Rc_\infty$, by an algorithm rather similar to the one which will construct the minimal automaton corresponding to any given finite state automaton (see for instance \cite{aho_seti_ullman:1986} algorithm 3.6.) On the other hand, there is also an easy lower approximation to the partition of $W$ in left cells. Indeed, it is easy to see that each left cell $C$ contains a whole left $\{s,t\}$-string as soon as it contains one of its elements. Denote $\Sc$ the smallest equivalence relation on $W$ which is compatible with $\{s,t\}$-strings for all non-commutaing pairs $\{s,t\}$. Again it is not hard to compute the partition $\Sc$. Our approach to left cells is to first compute the partitions $\Sc$ and $\Rc_\infty$; the former is a refinement of the latter. Any class for $\Rc_\infty$ which is also a class for $\Sc$ must be a left cell; for the remaining $\Rc_\infty$ classes we compute the $W$-graph of the class and get the left cells from there. It is known (\cite{kl:1979} section 5) that for type ${\rm A}$ the partitions $\Rc_\infty$ and $\Sc$ coincide; this seems also to be always the case in type ${\rm B}$. So in these cases the cell partition can be determined without any \kl\ computations whatsoever! Right cells can of course be deduced from left cells by inversion. I have to confess that I haven't found the time to study up on two-sided cells as much as I would have liked; currently their determination is implemented really brute force-like from the full two-sided $W$-graph of the group. This is certainly a point which should be improved in the future. Another thing that is currently missing from the program is the computation of Lusztig's $a$-function. Hmm... We now describe the member functions of the {\tt FiniteCoxGroup} class which are available for accessing the various partitions defined in this section. Only the actual \kl\ cells have a corresponding command in the default command interface, and can be printed out in various formats. The standard way of representing a partition of a set in $p$ classes, is through a function taking values in the set $\{0,\ldots,p-1\}$; and a general function on a set with $N$ elements is just a sequence of $N$ numbers. The various partition functions all return references to objects of type {\tt Partition}, defined in {\tt bits.h}; in addition to the actual partition function, this class contains the number of classes of the partition, and a number of member functions for sorting and traversing partitioned sets conveniently. Since some of these partitions may be rather expensive to compute, we avoid computing them more than once; the finite group structure contains predefined partition objects, initially empty, which are filled when first required. So after the first call, access should be instantaneous. \begin{itemize}\itemsep0pt \item[$\bullet$]{\tt lCell, rCell, lrCell}~: the partitions in ordinary \kl\ cells (these partitions may be printed out using the commands {\tt lcells}, {\tt rcells}, {\tt lrcells} from the default command interface); \item[$\bullet$]{\tt lUneqCell, rUneqCell, lrUneqCell}~: the partitions in \kl\ cells for unequal parameters (these partitions may be printed out using the commands {\tt lcells}, {\tt rcells}, {\tt lrcells} as above, after passing to ``unequal parameter mode'' using the command {\tt uneq}); \item[$\bullet$]{\tt lDescentPartition, rDescentPartition}~: the partitions in left and right descent classes; \item[$\bullet$]{\tt lGeneralizedTau, rGeneralizedTau}~: the partitions in equivalence classes for the generalized tau-invariant (the relation $\Rc_\infty$); \item[$\bullet$]{\tt lStringPartition, rStringPartition}~: the partitions for the equivalence relation $\Sc$ defined above. \end{itemize} \begin{thebibliography}{1} \bibitem{aho_seti_ullman:1986} A.V. {Aho, R. Seti and J.D. Ullman}. \newblock {\em {Compilers}}. \newblock Addison-Wesley, Reading, Massachussets, 1986. \bibitem{brink:1998} B.~Brink. \newblock {The set of dominance-minimal roots}. \newblock {\em {J. Algebra}}, {\bf 206}:371--412, 1998. \bibitem{brink_howlett:1993} B.~Brink and D.~Howlett. \newblock {A finiteness property and an automatic structure for Coxeter groups}. \newblock {\em {Math. Ann.}}, {\bf 296}:179--190, 1993. \bibitem{casselman:2002} W.~Casselman. \newblock {Computation in Coxeter groups. I. Multiplication.} \newblock {\em {Electron. J. Combin.}}, {\bf 9}(1):Research Paper 25, 22 pages, 2002. \bibitem{du_cloux:2002} {F. du} Cloux. \newblock {Computing Kazhdan-Lusztig polynomials in arbitrary Coxeter groups}. \newblock {\em {Experiment. Math.}}, {\bf 11}(3):387--397, 2002. \bibitem{kl:1979} D.~Kazhdan and G.~Lusztig. \newblock {Representations of Coxeter groups and Hecke algebras}. \newblock {\em {Invent. Math.}}, {\bf 53}:165--184, 1979. \bibitem{lusztig:1985} G.~Lusztig. \newblock {Cells in Affine Weyl Groups}. \newblock In {\em {Algebraic Groups and relaed topics (Kyoto/Nagoya 1983)}}, volume~6 of {\em Adv. Stud. Pure Math.}, pages 255--287, Amsterdam, 1985. North-Holland. \bibitem{vogan:1979} D.A. {Vogan Jr.} \newblock {A generalized $\tau$-invariant for the primitive spectrum of a semisimple Lie algebra}. \newblock {\em {Math. Ann.}}, {\bf 242}:209--224, 1979. \end{thebibliography} \end{document} positivity_final/coxbatch0000700000175000017500000000004710256222537017356 0ustar duclouxducloux00000000000000nice coxeter < coxdriver > /dev/null & positivity_final/coxdriver0000600000175000017500000000002210256222546017560 0ustar duclouxducloux00000000000000positivity H 4 qq