Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
gh-35038: Implement Milnor fiber and Coxeter complexes
    
Implements Milnor fiber and Coxeter complexes and their associated
posets. #34936

Dependencies: #34912
    
URL: #35038
Reported by: Travis Scrimshaw
Reviewer(s): Frédéric Chapoton, Travis Scrimshaw
  • Loading branch information
Release Manager committed Sep 15, 2023
2 parents 4103129 + 6d9ee05 commit 8c04027
Show file tree
Hide file tree
Showing 2 changed files with 299 additions and 0 deletions.
154 changes: 154 additions & 0 deletions src/sage/categories/finite_complex_reflection_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,107 @@ def base_change_matrix(self):
from sage.matrix.constructor import Matrix
return Matrix(list(self.independent_roots())).inverse()

def milnor_fiber_poset(self):
r"""
Return the Milnor fiber poset of ``self``.
The *Milnor fiber poset* of a finite complex reflection group `W`
is defined as the poset of (right) standard cosets `gW_J`,
where `J` is a subset of the index set `I` of `W`, ordered
by reverse inclusion. This is conjecturally a meet semilattice
if and only if `W` is well-generated.
EXAMPLES::
sage: W = ColoredPermutations(3, 2)
sage: P = W.milnor_fiber_poset()
sage: P
Finite meet-semilattice containing 34 elements
sage: R.<x> = ZZ[]
sage: sum(x**P.rank(elt) for elt in P)
18*x^2 + 15*x + 1
sage: W = ReflectionGroup(4) # optional - gap3
sage: P = W.milnor_fiber_poset() # optional - gap3
sage: P # optional - gap3
Finite meet-semilattice containing 41 elements
sage: sum(x**P.rank(elt) for elt in P) # optional - gap3
24*x^2 + 16*x + 1
sage: W = ReflectionGroup([4,2,2]) # optional - gap3
sage: W.is_well_generated() # optional - gap3
False
sage: P = W.milnor_fiber_poset() # optional - gap3
sage: P # optional - gap3
Finite poset containing 47 elements
sage: sum(x**P.rank(elt) for elt in P) # optional - gap3
16*x^3 + 24*x^2 + 6*x + 1
sage: P.is_meet_semilattice() # optional - gap3
False
"""
I = self.index_set()
data = {}
next_reprs = {(): [g for g in self]}
next_cosets = {(): [frozenset([g]) for g in next_reprs[()]]}
next_level = set((i, ()) for i in range(len(next_cosets[()])))
while next_level:
cur = next_level
cosets = next_cosets
reprs = next_reprs
next_level = set()
next_cosets = {}
next_reprs = {}
for Y in cur:
index, J = Y
for i in I:
if i in J:
continue
Jp = tuple(sorted(J + (i,)))
# See if the coset is already there
found_coset = False
if Jp in next_cosets:
rep = reprs[J][index]
for ii, C in enumerate(next_cosets[Jp]):
if rep in C:
found_coset = True
Yp = (reprs[J][index], J)
Xp = (next_reprs[Jp][ii], Jp)
if Xp in data:
data[Xp].append(Yp)
else:
data[Xp] = [Yp]
else:
next_cosets[Jp] = []
next_reprs[Jp] = []
if found_coset:
continue

# Otherwise build the coset
next_level.add((len(next_cosets[Jp]), Jp))
H = set(cosets[J][index])
to_test = [(g, i) for g in H]
while to_test:
g, j = to_test.pop()
gp = g.apply_simple_reflection(j, side='right')
if gp in H:
continue
H.add(gp)
to_test.extend((gp, j) for j in Jp)
rep = min(H, key=lambda g: g.length())
next_cosets[Jp].append(frozenset(H))
next_reprs[Jp].append(rep)
Yp = (reprs[J][index], J)
Xp = (rep, Jp)
if Xp in data:
data[Xp].append(Yp)
else:
data[Xp] = [Yp]
if self.is_well_generated():
from sage.combinat.posets.lattices import MeetSemilattice
return MeetSemilattice(data)
from sage.combinat.posets.posets import Poset
return Poset(data)

class ElementMethods:

@abstract_method(optional=True)
Expand Down Expand Up @@ -1079,6 +1180,59 @@ def coxeter_elements(self):
"""
return self.coxeter_element().conjugacy_class()

def milnor_fiber_complex(self):
r"""
Return the Milnor fiber complex of ``self``.
The *Milnor fiber complex* of a finite well-generated
complex reflection group `W` is the simplicial complex whose
face poset is given by :meth:`milnor_fiber_poset`. When `W`
is an irreducible Shephard group, it is also an equivariant
strong deformation retract of the Milnor fiber `f_1^{-1}(1)`,
where `f_1: V \to \CC` is the polynomial invariant of smallest
degree acting on the reflection representation `V`.
When `W` is a Coxeter group, this is isomorphic to the
:wikipedia:`Coxeter complex <Coxeter_complex>` of `W`.
EXAMPLES::
sage: W = ColoredPermutations(3, 2)
sage: C = W.milnor_fiber_complex()
sage: C.homology()
{0: 0, 1: Z x Z x Z x Z}
sage: W = ReflectionGroup(5) # optional - gap3
sage: C = W.milnor_fiber_complex() # optional - gap3
sage: C.homology() # optional - gap3
{0: 0, 1: Z^25}
"""
I = self.index_set()
cosets = {}
for i in I:
Ip = tuple([j for j in I if j != i])
cosets[Ip] = []
for g in self:
if any(g in C for C in cosets[Ip]):
continue
H = set([g])
to_test = [(g, j) for j in Ip]
while to_test:
h, j = to_test.pop()
hp = h.apply_simple_reflection(j, side='right')
if hp in H:
continue
H.add(hp)
to_test.extend((hp, j) for j in Ip)
cosets[Ip].append(frozenset(H))
verts = {}
for Ip in cosets:
for C in cosets[Ip]:
verts[C, Ip] = len(verts)
facets = [[verts[k] for k in verts if g in k[0]] for g in self]
from sage.topology.simplicial_complex import SimplicialComplex
return SimplicialComplex(facets)

class Irreducible(CategoryWithAxiom):
r"""
The category of finite irreducible well-generated
Expand Down
145 changes: 145 additions & 0 deletions src/sage/categories/finite_coxeter_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,151 @@ def permutahedron(self, point=None, base_ring=None):
from sage.geometry.polyhedron.constructor import Polyhedron
return Polyhedron(vertices=vertices, base_ring=base_ring)

def coxeter_poset(self):
r"""
Return the Coxeter poset of ``self``.
Let `W` be a Coxeter group. The *Coxeter poset* is defined as
the set of (right) standard cosets `gW_J`, where `J` is a
subset of the index set `I` of `W`, ordered by reverse inclusion.
This is equal to the face poset of the :meth:`Coxeter complex
<coxeter_complex()>`.
EXAMPLES::
sage: W = CoxeterGroup(['A', 3])
sage: P = W.coxeter_poset()
sage: P
Finite meet-semilattice containing 75 elements
sage: P.rank()
3
sage: W = WeylGroup(['B', 3])
sage: P = W.coxeter_poset()
sage: P
Finite meet-semilattice containing 147 elements
sage: P.rank()
3
sage: W = CoxeterGroup(['I', 7])
sage: P = W.coxeter_poset()
sage: P
Finite meet-semilattice containing 29 elements
sage: P.rank()
2
sage: W = CoxeterGroup(['H', 3])
sage: P = W.coxeter_poset()
sage: P
Finite meet-semilattice containing 363 elements
sage: P.rank()
3
sage: W = CoxeterGroup(['H', 3], implementation="permutation") # optional - gap3
sage: P = W.coxeter_poset() # optional - gap3
sage: P # optional - gap3
Finite meet-semilattice containing 363 elements
sage: P.rank() # optional - gap3
3
"""
I = self.index_set()
data = {}
next_level = set((g, ()) for g in self)
while next_level:
cur = next_level
next_level = set()
for Y in cur:
g, J = Y
for i in I:
if i in J:
continue
Jp = tuple(sorted(J + (i,)))
gp = g.coset_representative(Jp, side='right')
X = (gp, Jp)
if X in data:
data[X].append(Y)
else:
data[X] = [Y]
next_level.add(X)
from sage.combinat.posets.lattices import MeetSemilattice
return MeetSemilattice(data)

def coxeter_complex(self):
r"""
Return the Coxeter complex of ``self``.
Let `W` be a Coxeter group, and let `X` be the corresponding Tits
cone, which is constructed as the `W` orbit of the fundamental
chamber in the reflection representation. The *Coxeter complex*
of `W` is the simplicial complex `(X \setminus \{0\}) / \RR_{>0}`.
The face poset of this simplicial complex is given by the
:meth:`coxeter_poset()`. When `W` is a finite group, then the
Coxeter complex is homeomorphic to an `(n-1)`-dimensional sphere,
where `n` is the rank of `W`.
EXAMPLES::
sage: W = CoxeterGroup(['A', 3])
sage: C = W.coxeter_complex()
sage: C
Simplicial complex with 14 vertices and 24 facets
sage: C.homology()
{0: 0, 1: 0, 2: Z}
sage: W = WeylGroup(['B', 3])
sage: C = W.coxeter_complex()
sage: C
Simplicial complex with 26 vertices and 48 facets
sage: C.homology()
{0: 0, 1: 0, 2: Z}
sage: W = CoxeterGroup(['I', 7])
sage: C = W.coxeter_complex()
sage: C
Simplicial complex with 14 vertices and 14 facets
sage: C.homology()
{0: 0, 1: Z}
sage: W = CoxeterGroup(['H', 3])
sage: C = W.coxeter_complex()
sage: C
Simplicial complex with 62 vertices and 120 facets
sage: C.homology()
{0: 0, 1: 0, 2: Z}
sage: W = CoxeterGroup(['H', 3], implementation="permutation") # optional - gap3
sage: C = W.coxeter_complex() # optional - gap3
sage: C # optional - gap3
Simplicial complex with 62 vertices and 120 facets
sage: C.homology() # optional - gap3
{0: 0, 1: 0, 2: Z}
"""
I = self.index_set()
facets = {}
Ip = {i: tuple([j for j in I if j != i]) for i in I}
for g in self:
V = []
for i in I:
gp = g
D = gp.descents(side='right')
if D and D[0] == i:
D.pop(0)
while D:
gp = gp.apply_simple_reflection(D[0])
D = gp.descents(side='right')
if D and D[0] == i:
D.pop(0)
V.append((gp, Ip[i]))
facets[g] = V
verts = set()
for F in facets.values():
verts.update(F)
labels = {x: i for i,x in enumerate(verts)}
result = [[labels[v] for v in F] for F in facets.values()]
from sage.topology.simplicial_complex import SimplicialComplex
return SimplicialComplex(result)

class ElementMethods:

@cached_in_parent_method
Expand Down

0 comments on commit 8c04027

Please sign in to comment.