A demonstration of Sage + GAP4 + GAP3 + Chevie + Semigroupe
Let us create the Coxeter group W:
{{{id=1|
W = CoxeterGroup(["H",4]); W
///
}}}
It is constructed as a group of permutations, from root data given by
GAP3+Chevie (thanks to Franco’s interface):
sage: W._gap_group
CoxeterGroup(“H”,4)
sage: (W._gap_group).parent()
Gap3
with operations on permutations implemented in Sage:
{{{id=2|
W.an_element()^3
///
(1,5)(2,62)(3,7)(6,9)(8,12)(11,15)(13,17)(16,20)(18,22)(21,25)(26,29)(28,31)(30,33)(32,35)(34,37)(36,39)(38,41)(42,45)(46,48)(47,49)(50,52)(55,56)(57,58)(61,65)(63,67)(66,69)(68,72)(71,75)(73,77)(76,80)(78,82)(81,85)(86,89)(88,91)(90,93)(92,95)(94,97)(96,99)(98,101)(102,105)(106,108)(107,109)(110,112)(115,116)(117,118)
}}}
and group operations implemented in GAP:
{{{id=3|
len(W.conjugacy_classes_representatives())
///
34
}}}
{{{id=4|
W.cardinality()
///
14400
}}}
Now, assume we want to do intensive computations on this group,
requiring heavy access to the left and right Cayley graphs
(e.g. Bruhat interval calculations, representation theory, ...). Then
we can use Jean-Eric Pin’s Semigroupe, a software written in C:
{{{id=5|
S = semigroupe.AutomaticSemigroup(W.semigroup_generators(), W.one(), category = FiniteCoxeterGroups())
///
}}}
The following triggers the full expansion of the group and its Cayley
graph in memory:
{{{id=6|
S.cardinality()
///
14400
}}}
And we can now iterate through the elements, in length-lexicographic
order w.r.t. their reduced word:
{{{id=7|
sum( x^p.length() for p in S)
///
x^60 + 4*x^59 + 9*x^58 + 16*x^57 + 25*x^56 + 36*x^55 + 49*x^54 + 64*x^53 + 81*x^52 + 100*x^51 + 121*x^50 + 144*x^49 + 168*x^48 + 192*x^47 + 216*x^46 + 240*x^45 + 264*x^44 + 288*x^43 + 312*x^42 + 336*x^41 + 359*x^40 + 380*x^39 + 399*x^38 + 416*x^37 + 431*x^36 + 444*x^35 + 455*x^34 + 464*x^33 + 471*x^32 + 476*x^31 + 478*x^30 + 476*x^29 + 471*x^28 + 464*x^27 + 455*x^26 + 444*x^25 + 431*x^24 + 416*x^23 + 399*x^22 + 380*x^21 + 359*x^20 + 336*x^19 + 312*x^18 + 288*x^17 + 264*x^16 + 240*x^15 + 216*x^14 + 192*x^13 + 168*x^12 + 144*x^11 + 121*x^10 + 100*x^9 + 81*x^8 + 64*x^7 + 49*x^6 + 36*x^5 + 25*x^4 + 16*x^3 + 9*x^2 + 4*x + 1
}}}
{{{id=8|
S[0:10]
///
[[], [0], [1], [2], [3], [0, 1], [0, 2], [0, 3], [1, 0], [1, 2]]
}}}
{{{id=9|
S[-1]
///
[0, 1, 0, 1, 0, 2, 0, 1, 0, 1, 2, 0, 1, 0, 2, 3, 2, 0, 1, 0, 1, 2, 0, 1, 0, 2, 3, 2, 0, 1, 0, 1, 2, 0, 1, 0, 2, 3, 2, 0, 1, 0, 1, 2, 0, 1, 0, 2, 3, 2, 0, 1, 0, 1, 2, 0, 1, 0, 2, 3]
}}}
The elements of S are handles to C objects from Semigroupe:
{{{id=10|
x = S.an_element()
x
///
[0, 1, 2, 3]
}}}
Products are calculated by Semigroupe:
{{{id=11|
x * x
///
[0, 1, 0, 2, 0, 1, 3, 2]
}}}
Powering operations are handled by Sage:
{{{id=12|
x^3
///
[0, 1, 0, 2, 0, 1, 0, 2, 3, 2, 0, 1]
}}}
{{{id=13|
x^(10^10000)
///
}}}
Altogether, S is a full fledged Sage Coxeter group, which passes all
the generic tests:
{{{id=14|
TestSuite(S).run(verbose = True, skip = "_test_associativity")
///
}}}
And of course it works for general semigroups too, and can further
compute much more information about those, like the (Knuth-Bendix
completion of the) relations between the generators:
{{{id=15|
S.print_relations()
///
aa = 1
bb = 1
cb = bc
cc = 1
da = ad
db = bd
dd = 1
cac = aca
dcd = cdc
dcababcabacdcababcabacdcababcabacdcababcabacdc = cdcababcabacdcababcabacdcababcabacdcababcabacd
}}}
which contains the usual commutation + braid relations.
Let’s try now the 0-Hecke monoid:
{{{id=16|
from sage.combinat.j_trivial_monoids import *
S = semigroupe.AutomaticSemigroup(W.simple_projections(), W.one(), by_action = True)
S.cardinality()
///
48
}}}
{{{id=17|
S.print_relations()
///
aa = a
bb = b
ca = ac
cc = c
da = ad
db = bd
dd = d
cbc = bcb
dcd = cdc
ababacbabacbabcdcbabacbabcdcbabacbabcdcbabacbabcdcbabacbabcd = 0
}}}
Let us throw in more mathematical information:
{{{id=18|
W = CoxeterGroup(["A",3])
S = semigroupe.AutomaticSemigroup(W.simple_projections(), W.one(), by_action = True, category = FiniteJTrivialMonoids())
///
}}}
{{{id=19|
S.cardinality()
///
}}}
{{{id=20|
H = S.algebra(QQ)
H.orthogonal_idempotents()
///
}}}
More about Jtrivial monoids:
{{{id=21|
from sage.combinat.j_trivial_monoids import *
def pij(j): return lambda i: i if i != j+1 else j
pi2 = pij(2)
///
}}}
{{{id=22|
pi2(1), pi2(2), pi2(3), pi2(4)
///
(1, 2, 2, 4)
}}}
{{{id=23|
class NDPFMonoid(AutomaticMonoid):
def __init__(self, n):
ambient_monoid = DiscreteFunctions(range(1,n+1), action="right")
pi = Family(range(1, n), lambda j: ambient_monoid(pij(j)))
AutomaticMonoid.__init__(self, pi, one = ambient_monoid.one(),
category = (SubFiniteMonoidsOfFunctions(),
FiniteJTrivialMonoids()))
Mon = NDPFMonoid(3)
Mon.cardinality()
///
5
}}}
{{{id=24|
Mon.list()
///
[[], [1], [2], [1, 2], [2, 1]]
}}}
{{{id=25|
[ NDPFMonoid(n).cardinality() for n in range(6)]
///
[1, 1, 2, 5, 14, 42]
}}}
{{{id=26|
MuMon = mupad(Mon); MuMon
///
/ +- -+ \
| | 0, 1, 2, 3, 4 | |
| | | |
| | 1, 1, 4, 4, 4 | |
| | | |
Dom::MMonoid| | 2, 3, 2, 3, 4 | |
| | | |
| | 3, 3, 4, 4, 4 | |
| | | |
| | 4, 4, 4, 4, 4 | |
\ +- -+ /
}}}
{{{id=27|
MuMon.count()
///
5
}}}
{{{id=28|
MuAlg = mupad.Dom.MonoidAlgebra(MuMon); MuAlg
///
}}}
{{{id=29|
MuCMat = MuAlg.cartanInvariantsMatrix(); MuCMat
///
+- -+
| 1, 0, 0, 0 |
| |
| 0, 1, 1, 0 |
| |
| 0, 0, 1, 0 |
| |
| 0, 0, 0, 1 |
+- -+
}}}
{{{id=30|
MuCMat.sage()
///
[1 0 0 0]
[0 1 1 0]
[0 0 1 0]
[0 0 0 1]
}}}
{{{id=31|
M4 = NDPFMonoid(4)
var('q')
///
q
}}}
{{{id=32|
cartconj = M4.cartan_matrix(q); cartconj
///
[ 1 0 0 0 0 0 0 0]
[ 0 1 q q^2 0 0 0 0]
[ 0 0 1 q 0 0 0 0]
[ 0 0 0 1 0 0 0 0]
[ 0 0 0 0 1 0 q 0]
[ 0 0 0 0 q 1 q^2 0]
[ 0 0 0 0 0 0 1 0]
[ 0 0 0 0 0 0 0 1]
}}}
{{{id=33|
cart = M4.cartan_matrix_mupad(q); cart
///
[ 1 0 0 0 0 0 0 0]
[ 0 1 0 0 q 0 0 0]
[ 0 q 1 0 q^2 0 0 0]
[ 0 0 0 1 0 q^2 q 0]
[ 0 0 0 0 1 0 0 0]
[ 0 0 0 0 0 1 0 0]
[ 0 0 0 0 0 q 1 0]
[ 0 0 0 0 0 0 0 1]
}}}
{{{id=34|
def is_isomorphic_matrices(m1, m2):
coeffs1 = set([ c for row in m1 for c in row ])
coeffs2 = set([ c for row in m2 for c in row ])
if coeffs1 != coeffs2:
return False
f = sage.combinat.ranker.rank_from_list(sorted(coeffs1))
def graph(m):
m = matrix([[f(m[i,j]) for j in range(m.ncols()) ] for i in range(m.nrows())])
return DiGraph(m, multiple_edges = True)
return graph(m1).is_isomorphic(graph(m2))
///
}}}
{{{id=35|
is_isomorphic_matrices(cart, cartconj)
///
True
}}}
{{{id=36|
P4 = Posets(4); P4
///
Posets containing 4 vertices
}}}
{{{id=37|
P4.cardinality()
///
16
}}}
{{{id=38|
Pos = P4[9]; Pos.cover_relations()
///
[[0, 2], [1, 2], [2, 3]]
}}}
{{{id=39|
#Pos.plot()
///
}}}
{{{id=40|
MP = NDPFMonoidPoset(Pos); MP
///
NDPF monoid of Poset ([[0, 2], [1, 2], [2, 3]])
}}}
{{{id=41|
is_isomorphic_matrices(MP.cartan_matrix(q), MP.cartan_matrix_mupad(q))
///
True
}}}
{{{id=42|
@parallel()
def check_conj_parallel(Pos):
MP = NDPFMonoidPoset(Pos)
return is_isomorphic_matrices(MP.cartan_matrix(q),
MP.cartan_matrix_mupad(q))
///
}}}
{{{id=43|
for (((poset,), _), res) in check_conj_parallel(Posets(3).list()): print poset.cover_relations(), res
///
}}}
{{{id=44|
all(x[1] for x in check_conj_parallel(Posets(4).list()))
///
True
}}}
We finish with some character ring calculations:
{{{id=45|
attach /home/nthiery/work/frg/Articles/Hivert_Schilling_Thiery_HeckeMonoid/main.sage
M = BiHeckeMonoid(["A",3])
G = M.character_ring()
E = G.E(); T = G.T(); P = G.P()
///
}}}
{{{id=46|
M0 = M.fix_w0_monoid()
G0 = M0.character_ring()
S0 = G0.S(); P0 = G0.P()
///
}}}
{{{id=47|
for e in P0.basis():
print "Ind(",e, ")=", P(G.induce_from_M0(S0(e))) # indirect doctest
///
Ind( P[1234] )= P[1234]
Ind( P[2134] )= P[2134] + P[2314] + P[2341] + P[2413] + P[4213]
Ind( P[2314] )= P[2314] + P[2341]
Ind( P[3214] )= P[3214] + P[3241] + P[3421]
Ind( P[2341] )= P[2341]
Ind( P[3241] )= P[3241] + P[3421]
Ind( P[3421] )= P[3421]
Ind( P[4321] )= P[4321]
Ind( P[2431] )= P[2431] + P[4231]
Ind( P[4231] )= P[4231]
Ind( P[1324] )= P[1324] + P[1342] + P[3124] + P[3142] + P[3241] + P[3412] + P[4132]
Ind( P[3124] )= P[3124] + P[3142] + P[3241] + P[3412]
Ind( P[1342] )= P[1342] + P[3142] + P[3412] + P[4132]
Ind( P[3142] )= P[3142] + P[3412]
Ind( P[3412] )= P[3412]
Ind( P[4312] )= P[4312]
Ind( P[1432] )= P[1432] + P[4132] + P[4312]
Ind( P[4132] )= P[4132] + P[4312]
Ind( P[1243] )= P[1243] + P[1423] + P[2413] + P[2431] + P[4123]
Ind( P[2143] )= P[2143] + P[2413] + P[2431] + P[4213] + P[4231]
Ind( P[2413] )= P[2413] + P[2431] + P[4213] + P[4231]
Ind( P[4213] )= P[4213] + P[4231]
Ind( P[1423] )= P[1423] + P[4123]
Ind( P[4123] )= P[4123]
}}}
Behind the scene, it uses the cutting poset (to convert between
translation modules to simple modules), the character formula for
projective modules of J-Trivial monoids, the property that simple
modules for M0 are induced to translation modules for M, etc. Plus
inversion by matrix of linear morphism between finite dimensional
vector spaces. It also uses the expansion of the character of a
projective module for the BiHecke monoid in term of simple module, but
this one is hard-coded for type A3 (currently too expensive to
recalculate it). The framework supports q-characters; but few of the
rules above are implemented for them, since we do not know them yet