Skip to content

Commit

Permalink
sagemathgh-39397: details in braid groups
Browse files Browse the repository at this point in the history
    
some typing annotations, a few code details

including avoid the terrible use of `gens_dict_recursive`

### 📝 Checklist

- [x] The title is concise and informative.
- [x] The description explains in detail what this PR is about.
    
URL: sagemath#39397
Reported by: Frédéric Chapoton
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Feb 21, 2025
2 parents e6975be + 56c0322 commit 870aba2
Showing 1 changed file with 58 additions and 45 deletions.
103 changes: 58 additions & 45 deletions src/sage/groups/braid.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
Braid groups are implemented as a particular case of finitely presented groups,
but with a lot of specific methods for braids.
A braid group can be created by giving the number of strands, and the name of the generators::
A braid group can be created by giving the number of strands, and the name
of the generators::
sage: BraidGroup(3)
Braid group on 3 strands
Expand All @@ -15,8 +16,8 @@
sage: BraidGroup(3,'a,b').gens()
(a, b)
The elements can be created by operating with the generators, or by passing a list
with the indices of the letters to the group::
The elements can be created by operating with the generators, or by passing
a list with the indices of the letters to the group::
sage: B.<s0,s1,s2> = BraidGroup(4)
sage: s0*s1*s0
Expand Down Expand Up @@ -81,7 +82,8 @@
GroupMorphismWithGensImages,
)
from sage.groups.free_group import FreeGroup, is_FreeGroup
from sage.groups.perm_gps.permgroup_named import SymmetricGroup, SymmetricGroupElement
from sage.groups.perm_gps.permgroup_named import (SymmetricGroup,
SymmetricGroupElement)
from sage.libs.gap.libgap import libgap
from sage.matrix.constructor import identity_matrix, matrix
from sage.misc.cachefunc import cached_method
Expand All @@ -96,10 +98,11 @@
from sage.structure.richcmp import rich_to_bool, richcmp

lazy_import('sage.libs.braiding',
['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',
['leftnormalform', 'rightnormalform', 'centralizer',
'supersummitset', 'greatestcommondivisor',
'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset',
'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss',
'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings' ],
'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings'],
feature=sage__libs__braiding())
lazy_import('sage.knots.knot', 'Knot')

Expand Down Expand Up @@ -500,7 +503,8 @@ def permutation(self, W=None):
"""
return self.coxeter_group_element(W)

def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio=1, axes=False, **kwds):
def plot(self, color='rainbow', orientation='bottom-top', gap=0.05,
aspect_ratio=1, axes=False, **kwds):
"""
Plot the braid.
Expand Down Expand Up @@ -632,7 +636,7 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio

def plot3d(self, color='rainbow'):
"""
Plots the braid in 3d.
Plot the braid in 3d.
The following option is available:
Expand Down Expand Up @@ -830,6 +834,7 @@ def links_gould_matrix(self, symbolics=False):
r"""
Return the representation matrix of ``self`` according to the R-matrix
representation being attached to the quantum superalgebra `\mathfrak{sl}_q(2|1)`.
See [MW2012]_, section 3 and references given there.
INPUT:
Expand Down Expand Up @@ -861,15 +866,16 @@ def links_gould_matrix(self, symbolics=False):
M = rep[0][0].parent().one()
for i in self.Tietze():
if i > 0:
M = M*rep[i-1][0]
M = M * rep[i-1][0]
if i < 0:
M = M*rep[-i-1][1]
M = M * rep[-i-1][1]
return M

@cached_method
def links_gould_polynomial(self, varnames=None, use_symbolics=False):
r"""
Return the Links-Gould polynomial of the closure of ``self``.
See [MW2012]_, section 3 and references given there.
INPUT:
Expand Down Expand Up @@ -906,12 +912,13 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False):
mu = rep[ln - 1] # quantum trace factor
M = mu * self.links_gould_matrix(symbolics=use_symbolics)
d1, d2 = M.dimensions()
e = d1//4
e = d1 // 4
B = M.base_ring()
R = LaurentPolynomialRing(ZZ, varnames)

# partial quantum trace according to I. Marin section 2.5
part_trace = matrix(B, 4, 4, lambda i, j: sum(M[e * i + k, e * j + k] for k in range(e)))
part_trace = matrix(B, 4, 4, lambda i, j: sum(M[e * i + k, e * j + k]
for k in range(e)))
ptemp = part_trace[0, 0] # part_trace == psymb*M.parent().one()
if use_symbolics:
v1, v2 = R.variable_names()
Expand All @@ -922,13 +929,13 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False):
else:
ltemp = ptemp.lift().constant_coefficient()
# Since the result of the calculation is known to be a Laurent polynomial
# in t0 and t1 all exponents of ltemp must be divisable by 2
# in t0 and t1 all exponents of ltemp must be divisible by 2
L = ltemp.parent()
lred = L({(k[0]/2, k[1]/2): v for k, v in ltemp.monomial_coefficients().items()})
t0, t1 = R.gens()
return lred(t0, t1)

def tropical_coordinates(self):
def tropical_coordinates(self) -> list:
r"""
Return the tropical coordinates of ``self`` in the braid group `B_n`.
Expand Down Expand Up @@ -972,7 +979,7 @@ def tropical_coordinates(self):

from sage.rings.semirings.tropical_semiring import TropicalSemiring
T = TropicalSemiring(ZZ)
return [T(_) for _ in coord]
return [T(c) for c in coord]

def markov_trace(self, variab=None, normalized=True):
r"""
Expand Down Expand Up @@ -1640,7 +1647,7 @@ def right_normal_form(self):
B = self.parent()
return tuple([B(b) for b in rnf[:-1]] + [B.delta()**rnf[-1][0]])

def centralizer(self):
def centralizer(self) -> list:
"""
Return a list of generators of the centralizer of the braid.
Expand All @@ -1655,7 +1662,7 @@ def centralizer(self):
B = self.parent()
return [B._element_from_libbraiding(b) for b in c]

def super_summit_set(self):
def super_summit_set(self) -> list:
"""
Return a list with the super summit set of the braid.
Expand Down Expand Up @@ -1773,10 +1780,9 @@ def conjugating_braid(self, other):
cb = conjugatingbraid(self, other)
if not cb:
return None
else:
B = self.parent()
cb[0][0] %= 2
return B._element_from_libbraiding(cb)
B = self.parent()
cb[0][0] %= 2
return B._element_from_libbraiding(cb)

def is_conjugated(self, other) -> bool:
"""
Expand Down Expand Up @@ -1893,7 +1899,7 @@ def pure_conjugating_braid(self, other):
n2 = len(b2.Tietze())
return b2 if n2 <= n0 else b0

def ultra_summit_set(self):
def ultra_summit_set(self) -> list:
"""
Return a list with the orbits of the ultra summit set of ``self``.
Expand Down Expand Up @@ -1922,7 +1928,7 @@ def ultra_summit_set(self):
B = self.parent()
return [[B._element_from_libbraiding(i) for i in s] for s in uss]

def thurston_type(self):
def thurston_type(self) -> str:
"""
Return the thurston_type of ``self``.
Expand Down Expand Up @@ -2007,7 +2013,7 @@ def rigidity(self):
"""
return Integer(rigidity(self))

def sliding_circuits(self):
def sliding_circuits(self) -> list:
"""
Return the sliding circuits of the braid.
Expand Down Expand Up @@ -2304,7 +2310,7 @@ def ultra_summit_set_element(self):
B = self.parent()
return tuple([B._element_from_libbraiding(b) for b in to_uss])

def sliding_circuits_element(self):
def sliding_circuits_element(self) -> tuple:
r"""
Return an element of the braid's sliding circuits, and the conjugating
braid.
Expand All @@ -2320,7 +2326,7 @@ def sliding_circuits_element(self):
B = self.parent()
return tuple([B._element_from_libbraiding(b) for b in to_sc])

def trajectory(self):
def trajectory(self) -> list:
r"""
Return the braid's trajectory.
Expand All @@ -2338,7 +2344,7 @@ def trajectory(self):
B = self.parent()
return [B._element_from_libbraiding(b) for b in traj]

def cyclic_slidings(self):
def cyclic_slidings(self) -> list:
r"""
Return the braid's cyclic slidings.
Expand Down Expand Up @@ -2518,6 +2524,7 @@ def reduced_word(self):
def tuple_to_word(q_tuple):
return M.prod(self._gens[i]**exp
for i, exp in enumerate(q_tuple))

ret = {tuple_to_word(q_tuple): q_factor
for q_tuple, q_factor in self.tuples.items() if q_factor}
return self._algebra._from_dict(ret, remove_zeros=False)
Expand Down Expand Up @@ -2580,7 +2587,7 @@ def eps_monom(q_tuple):
return sum(q_factor * eps_monom(q_tuple)
for q_tuple, q_factor in self.tuples.items())

def __repr__(self):
def __repr__(self) -> str:
r"""
String representation of ``self``.
Expand Down Expand Up @@ -2616,7 +2623,7 @@ class BraidGroup_class(FiniteTypeArtinGroup):
"""
Element = Braid

def __init__(self, names):
def __init__(self, names) -> None:
"""
Python constructor.
Expand Down Expand Up @@ -2691,7 +2698,7 @@ def __init__(self, names):
# For caching hermitian form of unitary Burau representation
self._hermitian_form = None

def __reduce__(self):
def __reduce__(self) -> tuple:
"""
TESTS::
Expand All @@ -2704,7 +2711,7 @@ def __reduce__(self):
"""
return (BraidGroup_class, (self.variable_names(), ))

def _repr_(self):
def _repr_(self) -> str:
"""
Return a string representation.
Expand Down Expand Up @@ -2795,7 +2802,7 @@ def an_element(self):
"""
return self.gen(0)

def some_elements(self):
def some_elements(self) -> list:
"""
Return a list of some elements of the braid group.
Expand All @@ -2812,7 +2819,7 @@ def some_elements(self):
elements_list.append(elements_list[-1]**self.strands())
return elements_list

def _standard_lift_Tietze(self, p):
def _standard_lift_Tietze(self, p) -> tuple:
"""
Helper for :meth:`_standard_lift_Tietze`.
Expand Down Expand Up @@ -2840,8 +2847,7 @@ def _standard_lift_Tietze(self, p):
(1, 2, 3, 4, 1, 2)
"""
G = SymmetricGroup(self.strands())
pl = G(p)
return tuple(pl.reduced_word())
return tuple(G(p).reduced_word())

@cached_method
def _links_gould_representation(self, symbolics=False):
Expand Down Expand Up @@ -2887,8 +2893,9 @@ def _links_gould_representation(self, symbolics=False):
else:
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
LR = LaurentPolynomialRing(ZZ, 's0r, s1r')
s0r, s1r = LR.gens()
PR = PolynomialRing(LR, 'Yr')
s0r, s1r, Yr = PR.gens_dict_recursive().values()
Yr = PR.gen()
pqr = Yr**2 + (s0r**2 - 1) * (s1r**2 - 1)
BR = PR.quotient_ring(pqr)
s0 = BR(s0r)
Expand Down Expand Up @@ -3453,9 +3460,10 @@ def mirror_involution(self):
r"""
Return the mirror involution of ``self``.
This automorphism maps a braid to another one by replacing each generator
in its word by the inverse. In general this is different from the inverse
of the braid since the order of the generators in the word is not reversed.
This automorphism maps a braid to another one by replacing
each generator in its word by the inverse. In general this is
different from the inverse of the braid since the order of the
generators in the word is not reversed.
EXAMPLES::
Expand Down Expand Up @@ -3519,7 +3527,7 @@ def presentation_two_generators(self, isomorphisms=False):
h2 = G.hom(codomain=self, im_gens=[self(a) for a in L2], check=False)
return (G, h1, h2)

def epimorphisms(self, H):
def epimorphisms(self, H) -> list:
r"""
Return the epimorphisms from ``self`` to ``H``, up to automorphism of `H` passing
through the :meth:`two generator presentation
Expand Down Expand Up @@ -3552,12 +3560,15 @@ def epimorphisms(self, H):
Gg = libgap(G)
Hg = libgap(H)
gquotients = Gg.GQuotients(Hg)
hom1g = libgap.GroupHomomorphismByImagesNC(G0g, Gg, [libgap(hom1(u)) for u in self.gens()])
hom1g = libgap.GroupHomomorphismByImagesNC(G0g, Gg,
[libgap(hom1(u))
for u in self.gens()])
g0quotients = [hom1g * h for h in gquotients]
res = []
# the following closure is needed to attach a specific value of quo to
# each function in the different morphisms
fmap = lambda tup: (lambda a: H(prod(tup[abs(i)-1]**sign(i) for i in a.Tietze())))
fmap = lambda tup: (lambda a: H(prod(tup[abs(i)-1]**sign(i)
for i in a.Tietze())))
for quo in g0quotients:
tup = tuple(H(quo.ImageElm(i.gap()).sage()) for i in self.gens())
fhom = GroupMorphismWithGensImages(HomSpace, fmap(tup))
Expand Down Expand Up @@ -3685,22 +3696,24 @@ class group of the punctured disk.
sage: A = B.mapping_class_action(F)
sage: A
Right action by Braid group on 4 strands on Free Group on generators {x0, x1, x2, x3}
Right action by Braid group on 4 strands on Free Group
on generators {x0, x1, x2, x3}
sage: A(x0, s1)
x0
sage: A(x1, s1)
x1*x2*x1^-1
sage: A(x1^-1, s1)
x1*x2^-1*x1^-1
"""
def __init__(self, G, M):
def __init__(self, G, M) -> None:
"""
TESTS::
sage: B = BraidGroup(3)
sage: G = FreeGroup('a, b, c')
sage: B.mapping_class_action(G) # indirect doctest
Right action by Braid group on 3 strands on Free Group on generators {a, b, c}
Right action by Braid group on 3 strands on Free Group
on generators {a, b, c}
"""
import operator
Action.__init__(self, G, M, False, operator.mul)
Expand Down

0 comments on commit 870aba2

Please sign in to comment.