99AUTHORS:
1010
1111- Travis Scrimshaw (2018-02-05): Initial version
12+ - Travis Scrimshaw (2025-01-30): Allowed general construction; implemented
13+ general Burau representation
14+
15+ .. TODO::
16+
17+ Implement affine type Artin groups with their well-known embeddings into
18+ the classical braid group.
1219"""
1320
1421# ****************************************************************************
15- # Copyright (C) 2018 Travis Scrimshaw <tcscrims at gmail.com>
22+ # Copyright (C) 2018-2025 Travis Scrimshaw <tcscrims at gmail.com>
1623#
1724# This program is free software: you can redistribute it and/or modify
1825# it under the terms of the GNU General Public License as published by
2633from sage .groups .free_group import FreeGroup
2734from sage .groups .finitely_presented import FinitelyPresentedGroup , FinitelyPresentedGroupElement
2835from sage .misc .cachefunc import cached_method
36+ from sage .misc .lazy_attribute import lazy_attribute
2937from sage .rings .infinity import Infinity
3038from sage .structure .richcmp import richcmp , rich_to_bool
3139from sage .structure .unique_representation import UniqueRepresentation
@@ -156,6 +164,132 @@ def coxeter_group_element(self, W=None):
156164 In = W .index_set ()
157165 return W .prod (s [In [abs (i )- 1 ]] for i in self .Tietze ())
158166
167+ def burau_matrix (self , var = 't' , reduced = False ):
168+ r"""
169+ Return the Burau matrix of the Artin group element.
170+
171+ Following [BQ2024]_, the (generalized) Burau representation of an
172+ Artin group is defined by deforming the reflection representation
173+ of the corresponding Coxeter group. However, we substitute
174+ `q \mapsto -t` from [BQ2024]_ to match the unitary
175+
176+ INPUT:
177+
178+ - ``var`` -- string (default: ``'t'``); the name of the
179+ variable in the entries of the matrix
180+
181+ OUTPUT:
182+
183+ The Burau matrix of the Artin group element over the Laurent
184+ polynomial ring in the variable ``var``.
185+
186+ EXAMPLES::
187+
188+ sage: A.<s1,s2,s3> = ArtinGroup(['B',3])
189+ sage: B1 = s1.burau_matrix()
190+ sage: B2 = s2.burau_matrix()
191+ sage: B3 = s3.burau_matrix()
192+ sage: [B1, B2, B3]
193+ [
194+ [-t^2 t 0] [ 1 0 0] [ 1 0 0]
195+ [ 0 1 0] [ t -t^2 a*t] [ 0 1 0]
196+ [ 0 0 1], [ 0 0 1], [ 0 a*t -t^2]
197+ ]
198+ sage: B1 * B2 * B1 == B2 * B1 * B2
199+ True
200+ sage: B2 * B3 * B2 * B3 == B3 * B2 * B3 * B2
201+ True
202+ sage: B1 * B3 == B3 * B1
203+ True
204+ sage: (~s1).burau_matrix() * B1 == 1
205+ True
206+
207+ We verify the example in Theorem 4.1 of [BQ2024]_::
208+
209+ sage: A.<s1,s2,s3,s4> = ArtinGroup(['A', 3, 1])
210+ sage: [g.burau_matrix() for g in A.gens()]
211+ [
212+ [-t^2 t 0 t] [ 1 0 0 0] [ 1 0 0 0]
213+ [ 0 1 0 0] [ t -t^2 t 0] [ 0 1 0 0]
214+ [ 0 0 1 0] [ 0 0 1 0] [ 0 t -t^2 t]
215+ [ 0 0 0 1], [ 0 0 0 1], [ 0 0 0 1],
216+ <BLANKLINE>
217+ [ 1 0 0 0]
218+ [ 0 1 0 0]
219+ [ 0 0 1 0]
220+ [ t 0 t -t^2]
221+ ]
222+ sage: a = s3^2 * s4 * s3 * s2 *s1 * ~s3 * s4 * s3 * s2 * s1^-2 * s4
223+ sage: b = s1^2 * ~s2 * s4 * s1 * ~s3 * s2 * ~s4 * s3 * s1 * s4 * s1 * ~s2 * s4^-2 * s3
224+ sage: alpha = a * s3 * ~a
225+ sage: beta = b * s2 * ~b
226+ sage: elm = alpha * beta * ~alpha * ~beta
227+ sage: print(elm.Tietze())
228+ (3, 3, 4, 3, 2, 1, -3, 4, 3, 2, -1, -1, 4, 3, -4, 1, 1, -2, -3,
229+ -4, 3, -1, -2, -3, -4, -3, -3, 1, 1, -2, 4, 1, -3, 2, -4, 3, 1,
230+ 4, 1, -2, -4, -4, 3, 2, -3, 4, 4, 2, -1, -4, -1, -3, 4, -2, 3,
231+ -1, -4, 2, -1, -1, 3, 3, 4, 3, 2, 1, -3, 4, 3, 2, -1, -1, 4,
232+ -3, -4, 1, 1, -2, -3, -4, 3, -1, -2, -3, -4, -3, -3, 1, 1, -2,
233+ 4, 1, -3, 2, -4, 3, 1, 4, 1, -2, -4, -4, 3, -2, -3, 4, 4, 2,
234+ -1, -4, -1, -3, 4, -2, 3, -1, -4, 2, -1, -1)
235+ sage: elm.burau_matrix()
236+ [1 0 0 0]
237+ [0 1 0 0]
238+ [0 0 1 0]
239+ [0 0 0 1]
240+
241+ Next, we show ``elm`` is not the identity by using the embedding of
242+ the affine braid group `\widetilde{B}_n \to B_{n+1}`::
243+
244+ sage: B.<t1,t2,t3,t4> = BraidGroup(5)
245+ sage: D = t1 * t2 * t3 * t4^2
246+ sage: t0 = D * t3 * ~D
247+ sage: t0*t1*t0 == t1*t0*t1
248+ True
249+ sage: t0*t2 == t2*t0
250+ True
251+ sage: t0*t3*t0 == t3*t0*t3
252+ True
253+ sage: T = [t0, t1, t2, t3]
254+ sage: emb = B.prod(T[i-1] if i > 0 else ~T[-i-1] for i in elm.Tietze())
255+ sage: emb.is_one()
256+ False
257+
258+ Since the Burau representation does not respect the group embedding,
259+ the corresponding `B_5` element's Burau matrix is not the identity
260+ (Bigelow gave an example of the representation not being faithful for
261+ `B_5`, but it is still open for `B_4`)::
262+
263+ sage: emb.burau_matrix() != 1
264+ True
265+
266+ We also verify the result using the elements in [BQ2024]_ Remark 4.2::
267+
268+ sage: ap = s3 * s1 * s2 * s1 * ~s3 * s4 * s2 * s3 * s2 * ~s3 * s1^-2 * s4
269+ sage: bp = s1 * ~s4 * s1^2 * s3^-2 * ~s2 * s4 * s1 * ~s3 * s2 * ~s4 * s3 * s1 * s4 * s1 * ~s2 * s4^-2 * s3
270+ sage: alpha = ap * s3 * ~ap
271+ sage: beta = bp * s2 * ~bp
272+ sage: elm = alpha * beta * ~alpha * ~beta
273+ sage: elm.burau_matrix()
274+ [1 0 0 0]
275+ [0 1 0 0]
276+ [0 0 1 0]
277+ [0 0 0 1]
278+
279+ REFERENCES:
280+
281+ - [BQ2024]_
282+ """
283+ gens , invs = self .parent ()._burau_generators
284+ MS = gens [0 ].parent ()
285+ ret = MS .prod (gens [i - 1 ] if i > 0 else invs [- i - 1 ] for i in self .Tietze ())
286+
287+ if var == 't' :
288+ return ret
289+ from sage .rings .polynomial .laurent_polynomial_ring import LaurentPolynomialRing
290+ poly_ring = LaurentPolynomialRing (ret .base_ring ().base_ring (), var )
291+ return ret .change_ring (poly_ring )
292+
159293
160294class FiniteTypeArtinGroupElement (ArtinGroupElement ):
161295 """
@@ -453,7 +587,7 @@ def __classcall_private__(cls, coxeter_data, names=None):
453587 from sage .groups .raag import RightAngledArtinGroup
454588 return RightAngledArtinGroup (coxeter_data .coxeter_graph (), names )
455589 if not coxeter_data .is_finite ():
456- raise NotImplementedError
590+ return super (). __classcall__ ( cls , coxeter_data , names )
457591 if coxeter_data .coxeter_type ().cartan_type ().type () == 'A' :
458592 from sage .groups .braid import BraidGroup
459593 return BraidGroup (coxeter_data .rank ()+ 1 , names )
@@ -476,15 +610,17 @@ def __init__(self, coxeter_matrix, names):
476610 rels = []
477611 # Generate the relations based on the Coxeter graph
478612 I = coxeter_matrix .index_set ()
613+ gens = free_group .gens ()
479614 for ii , i in enumerate (I ):
480- for j in I [ii + 1 :]:
615+ for jj , j in enumerate ( I [ii + 1 :], start = ii + 1 ) :
481616 m = coxeter_matrix [i , j ]
482617 if m == Infinity : # no relation
483618 continue
484- elt = [i , j ] * m
485- for ind in range (m , 2 * m ):
486- elt [ind ] = - elt [ind ]
487- rels .append (free_group (elt ))
619+ elt = (gens [ii ] * gens [jj ]) ** (m // 2 )
620+ if m % 2 == 1 :
621+ elt = elt * gens [ii ] * ~ gens [jj ]
622+ elt = elt * (~ gens [ii ] * ~ gens [jj ]) ** (m // 2 )
623+ rels .append (elt )
488624 FinitelyPresentedGroup .__init__ (self , free_group , tuple (rels ))
489625
490626 def _repr_ (self ):
@@ -688,6 +824,153 @@ def _standard_lift(self, w):
688824 """
689825 return self (self ._standard_lift_Tietze (w ))
690826
827+ @lazy_attribute
828+ def _burau_generators (self ):
829+ """
830+ The Burau matrices for the generators of ``self`` and their inverses.
831+
832+ EXAMPLES::
833+
834+ sage: A = ArtinGroup(['G',2])
835+ sage: A._burau_generators
836+ [[
837+ [-t^2 a*t] [ 1 0]
838+ [ 0 1], [ a*t -t^2]
839+ ],
840+ [
841+ [ -t^-2 a*t^-1] [ 1 0]
842+ [ 0 1], [a*t^-1 -t^-2]
843+ ]]
844+
845+ sage: A = ArtinGroup(['H',3])
846+ sage: A._burau_generators
847+ [[
848+ [-t^2 t 0] [ 1 0 0]
849+ [ 0 1 0] [ t -t^2 (1/2*a + 1/2)*t]
850+ [ 0 0 1], [ 0 0 1],
851+ <BLANKLINE>
852+ [ 1 0 0]
853+ [ 0 1 0]
854+ [ 0 (1/2*a + 1/2)*t -t^2]
855+ ],
856+ [
857+ [-t^-2 t^-1 0]
858+ [ 0 1 0]
859+ [ 0 0 1],
860+ <BLANKLINE>
861+ [ 1 0 0]
862+ [ t^-1 -t^-2 (1/2*a + 1/2)*t^-1]
863+ [ 0 0 1],
864+ <BLANKLINE>
865+ [ 1 0 0]
866+ [ 0 1 0]
867+ [ 0 (1/2*a + 1/2)*t^-1 -t^-2]
868+ ]]
869+
870+ sage: CM = matrix([[1,4,7], [4,1,10], [7,10,1]])
871+ sage: A = ArtinGroup(CM)
872+ sage: gens = A._burau_generators[0]; gens
873+ [
874+ [ -t^2 (E(8) - E(8)^3)*t (-E(7)^3 - E(7)^4)*t]
875+ [ 0 1 0]
876+ [ 0 0 1],
877+ <BLANKLINE>
878+ [ 1 0 0]
879+ [ (E(8) - E(8)^3)*t -t^2 (E(20) - E(20)^9)*t]
880+ [ 0 0 1],
881+ <BLANKLINE>
882+ [ 1 0 0]
883+ [ 0 1 0]
884+ [(-E(7)^3 - E(7)^4)*t (E(20) - E(20)^9)*t -t^2]
885+ ]
886+ sage: all(gens[i] * A._burau_generators[1][i] == 1 for i in range(3))
887+ True
888+ sage: B1, B2, B3 = gens
889+ sage: (B1 * B2)^2 == (B2 * B1)^2
890+ True
891+ sage: (B2 * B3)^5 == (B3 * B2)^5
892+ True
893+ sage: B1 * B3 * B1 * B3 * B1 * B3 * B1 == B3 * B1 * B3 * B1 * B3 * B1 * B3
894+ True
895+ """
896+ data = self .coxeter_type ()
897+ coxeter_matrix = self .coxeter_matrix ()
898+ n = coxeter_matrix .rank ()
899+
900+ # Determine the base field
901+ if data .is_simply_laced ():
902+ from sage .rings .integer_ring import ZZ
903+ base_ring = ZZ
904+ elif data .is_finite ():
905+ from sage .rings .number_field .number_field import QuadraticField
906+ letter = data .cartan_type ().type ()
907+ if letter in ['B' , 'C' , 'F' ]:
908+ base_ring = QuadraticField (2 )
909+ elif letter == 'G' :
910+ base_ring = QuadraticField (3 )
911+ elif letter == 'H' :
912+ base_ring = QuadraticField (5 )
913+ else :
914+ from sage .rings .universal_cyclotomic_field import UniversalCyclotomicField
915+ base_ring = UniversalCyclotomicField ()
916+ else :
917+ from sage .rings .universal_cyclotomic_field import UniversalCyclotomicField
918+ base_ring = UniversalCyclotomicField ()
919+
920+ # Construct the matrices
921+ from sage .matrix .args import SparseEntry
922+ from sage .matrix .matrix_space import MatrixSpace
923+ from sage .rings .polynomial .laurent_polynomial_ring import LaurentPolynomialRing
924+ import sage .rings .abc
925+ poly_ring = LaurentPolynomialRing (base_ring , 't' )
926+ q = - poly_ring .gen ()
927+ MS = MatrixSpace (poly_ring , n , sparse = True )
928+ one = MS .one ()
929+ # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
930+ if isinstance (base_ring , sage .rings .abc .UniversalCyclotomicField ):
931+ E = base_ring .gen
932+
933+ def val (x ):
934+ if x == - 1 :
935+ return 2 * q
936+ elif x == 1 :
937+ return 1 + q ** 2
938+ else :
939+ return q * (E (2 * x ) + ~ E (2 * x ))
940+ elif isinstance (base_ring , sage .rings .abc .NumberField_quadratic ):
941+ from sage .rings .universal_cyclotomic_field import UniversalCyclotomicField
942+ E = UniversalCyclotomicField ().gen
943+
944+ def val (x ):
945+ if x == - 1 :
946+ return 2 * q
947+ elif x == 1 :
948+ return 1 + q ** 2
949+ else :
950+ return q * base_ring ((E (2 * x ) + ~ E (2 * x )).to_cyclotomic_field ())
951+ else :
952+ def val (x ):
953+ if x == - 1 :
954+ return 2 * q
955+ elif x == 1 :
956+ return 1 + q ** 2
957+ elif x == 2 :
958+ return 0
959+ elif x == 3 :
960+ return q
961+ else :
962+ from sage .functions .trig import cos
963+ from sage .symbolic .constants import pi
964+ return q * base_ring (2 * cos (pi / x ))
965+ index_set = data .index_set ()
966+ gens = [one - MS ([SparseEntry (i , j , val (coxeter_matrix [index_set [i ], index_set [j ]]))
967+ for j in range (n )])
968+ for i in range (n )]
969+ invs = [one - q ** - 2 * MS ([SparseEntry (i , j , val (coxeter_matrix [index_set [i ], index_set [j ]]))
970+ for j in range (n )])
971+ for i in range (n )]
972+ return [gens , invs ]
973+
691974 Element = ArtinGroupElement
692975
693976
0 commit comments