def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): """ Initiate the Coxeter matrix from a matrix. TESTS:: sage: CM = CoxeterMatrix([[1,2],[2,1]]); CM [1 2] [2 1] sage: CM = CoxeterMatrix([[1,-1],[-1,1]]); CM [ 1 -1] [-1 1] sage: CM = CoxeterMatrix([[1,-1.5],[-1.5,1]]); CM [ 1.00000000000000 -1.50000000000000] [-1.50000000000000 1.00000000000000] sage: CM = CoxeterMatrix([[1,-3/2],[-3/2,1]]); CM [ 1 -3/2] [-3/2 1] sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,-1],[5,-1,1]]); CM [ 1 -3/2 5] [-3/2 1 -1] [ 5 -1 1] sage: CM = CoxeterMatrix([[1,-3/2,5],[-3/2,1,oo],[5,oo,1]]); CM [ 1 -3/2 5] [-3/2 1 -1] [ 5 -1 1] """ # Check that the data is valid check_coxeter_matrix(data) M = matrix(data) n = M.ncols() base_ring = M.base_ring() if not coxeter_type: if n == 1: coxeter_type = CoxeterType(['A', 1]) elif coxeter_type_check: coxeter_type = recognize_coxeter_type_from_matrix(M, index_set) else: coxeter_type = None raw_data = M.list() mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), raw_data, coxeter_type, index_set) mat._subdivisions = M._subdivisions return mat
def bilinear_form(self, R=None): r""" Return the bilinear form of ``self``. EXAMPLES:: sage: CoxeterType(['A', 2, 1]).bilinear_form() [ 1 -1/2 -1/2] [-1/2 1 -1/2] [-1/2 -1/2 1] sage: CoxeterType(['H', 3]).bilinear_form() [ 1 -1/2 0] [ -1/2 1 1/2*E(5)^2 + 1/2*E(5)^3] [ 0 1/2*E(5)^2 + 1/2*E(5)^3 1] sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) sage: C.bilinear_form() [ 1 -1 -1] [-1 1 -1] [-1 -1 1] """ return CoxeterType.bilinear_form(self, R=R)
def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): """ Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. EXAMPLES: Some infinite ones:: sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]]) sage: C.is_finite() # indirect doctest False sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) sage: C.is_finite() # indirect doctest False Some finite ones:: sage: m = matrix(CoxeterMatrix(['D', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: m = matrix(CoxeterMatrix(['H', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10] sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10] sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6] sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7] sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8] sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4] sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2] sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 3] sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() Coxeter type of ['I', 100] Some affine graphs:: sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 1, 1] sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10, 1] sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10, 1] sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['C', 10, 1] sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10, 1] sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6, 1] sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7, 1] sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8, 1] sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4, 1] sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2, 1] TESTS: Check that we detect relabellings:: sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c']) sage: M.coxeter_type() Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'} sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix sage: for C in CoxeterMatrix.samples(): ....: relabelling_perm = Permutations(C.index_set()).random_element() ....: relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())} ....: relabeled_matrix = C.relabel(relabelling_dict)._matrix ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm) ....: if C.is_finite() or C.is_affine(): ....: assert recognized_type == C.coxeter_type() We check the rank 2 cases (:trac:`20419`):: sage: for i in range(2, 10): ....: M = matrix([[1,i],[i,1]]) ....: CoxeterMatrix(M).coxeter_type() Coxeter type of A1xA1 relabelled by {1: 2} Coxeter type of ['A', 2] Coxeter type of ['B', 2] Coxeter type of ['I', 5] Coxeter type of ['G', 2] Coxeter type of ['I', 7] Coxeter type of ['I', 8] Coxeter type of ['I', 9] sage: CoxeterMatrix(matrix([[1,-1],[-1,1]]), index_set=[0,1]).coxeter_type() Coxeter type of ['A', 1, 1] """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) G = Graph([[index_set[i], index_set[j], coxeter_matrix[i, j]] for i in range(n) for j in range(i, n) if coxeter_matrix[i, j] not in [1, 2]]) G.add_vertices(index_set) types = [] for S in G.connected_components_subgraphs(): r = S.num_verts() # Handle the special cases first if r == 1: types.append(CoxeterType(['A', 1]).relabel({1: S.vertices()[0]})) continue if r == 2: # Type B2, G2, or I_2(p) e = S.edge_labels()[0] if e == 3: # Can't be 2 because it is connected ct = CoxeterType(['A', 2]) elif e == 4: ct = CoxeterType(['B', 2]) elif e == 6: ct = CoxeterType(['G', 2]) elif e > 0 and e < float('inf'): # Remaining non-affine types ct = CoxeterType(['I', e]) else: # Otherwise it is infinite dihedral group Z_2 \ast Z_2 ct = CoxeterType(['A', 1, 1]) if not ct.is_affine(): types.append( ct.relabel({ 1: S.vertices()[0], 2: S.vertices()[1] })) else: types.append( ct.relabel({ 0: S.vertices()[0], 1: S.vertices()[1] })) continue test = [['A', r], ['B', r], ['A', r - 1, 1]] if r >= 3: if r == 3: test += [['G', 2, 1], ['H', 3]] test.append(['C', r - 1, 1]) if r >= 4: if r == 4: test += [['F', 4], ['H', 4]] test += [['D', r], ['B', r - 1, 1]] if r >= 5: if r == 5: test.append(['F', 4, 1]) test.append(['D', r - 1, 1]) if r == 6: test.append(['E', 6]) elif r == 7: test += [['E', 7], ['E', 6, 1]] elif r == 8: test += [['E', 8], ['E', 7, 1]] elif r == 9: test.append(['E', 8, 1]) found = False for ct in test: ct = CoxeterType(ct) T = ct.coxeter_graph() iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if not found: return None return CoxeterType(types)
def __classcall_private__(cls, data=None, index_set=None, coxeter_type=None, cartan_type=None, coxeter_type_check=True): r""" A Coxeter matrix can we created via a graph, a Coxeter type, or a matrix. .. NOTE:: To disable the Coxeter type check, use the optional argument ``coxeter_type_check = False``. EXAMPLES:: sage: C = CoxeterMatrix(['A',1,1],['a','b']) sage: C2 = CoxeterMatrix([[1, -1], [-1, 1]]) sage: C3 = CoxeterMatrix(matrix([[1, -1], [-1, 1]]), [0, 1]) sage: C == C2 and C == C3 True Check with `\infty` because of the hack of using `-1` to represent `\infty` in the Coxeter matrix:: sage: G = Graph([(0, 1, 3), (1, 2, oo)]) sage: W1 = CoxeterMatrix([[1, 3, 2], [3, 1, -1], [2, -1, 1]]) sage: W2 = CoxeterMatrix(G) sage: W1 == W2 True sage: CoxeterMatrix(W1.coxeter_graph()) == W1 True The base ring of the matrix depends on the entries given:: sage: CoxeterMatrix([[1,-1],[-1,1]])._matrix.base_ring() Integer Ring sage: CoxeterMatrix([[1,-3/2],[-3/2,1]])._matrix.base_ring() Rational Field sage: CoxeterMatrix([[1,-1.5],[-1.5,1]])._matrix.base_ring() Real Field with 53 bits of precision """ if not data: if coxeter_type: data = CoxeterType(coxeter_type) elif cartan_type: data = CoxeterType(CartanType(cartan_type)) # Special cases with no arguments passed if not data: data = [] n = 0 index_set = tuple() coxeter_type = None base_ring = ZZ mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), data, coxeter_type, index_set) mat._subdivisions = None return mat if isinstance(data, CoxeterMatrix): # Initiate from itself return data # Initiate from a graph: # TODO: Check if a CoxeterDiagram once implemented if isinstance(data, Graph): return cls._from_graph(data, coxeter_type_check) # Get the Coxeter type coxeter_type = None from sage.combinat.root_system.cartan_type import CartanType_abstract if isinstance(data, CartanType_abstract): coxeter_type = data.coxeter_type() else: try: coxeter_type = CoxeterType(data) except (TypeError, ValueError, NotImplementedError): pass # Initiate from a Coxeter type if coxeter_type: return cls._from_coxetertype(coxeter_type) # TODO:: remove when oo is possible in matrices. n = len(data[0]) data = [x if x != infinity else -1 for r in data for x in r] data = matrix(n, n, data) # until here # Get the index set if index_set: index_set = tuple(index_set) else: index_set = tuple(range(1, n + 1)) if len(set(index_set)) != n: raise ValueError("the given index set is not valid") return cls._from_matrix(data, coxeter_type, index_set, coxeter_type_check)
def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): """ Return the Coxeter type of ``coxeter_matrix`` if known, otherwise return ``None``. EXAMPLES: Some infinite ones:: sage: C = CoxeterMatrix([[1,3,2],[3,1,-1],[2,-1,1]]) sage: C.is_finite() # indirect doctest False sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) sage: C.is_finite() # indirect doctest False Some finite ones:: sage: m = matrix(CoxeterMatrix(['D', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: m = matrix(CoxeterMatrix(['H', 4])) sage: CoxeterMatrix(m).is_finite() # indirect doctest True sage: CoxeterMatrix(CoxeterType(['A',10]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10] sage: CoxeterMatrix(CoxeterType(['B',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['C',10]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10] sage: CoxeterMatrix(CoxeterType(['D',10]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10] sage: CoxeterMatrix(CoxeterType(['E',6]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6] sage: CoxeterMatrix(CoxeterType(['E',7]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7] sage: CoxeterMatrix(CoxeterType(['E',8]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8] sage: CoxeterMatrix(CoxeterType(['F',4]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4] sage: CoxeterMatrix(CoxeterType(['G',2]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2] sage: CoxeterMatrix(CoxeterType(['H',3]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 3] sage: CoxeterMatrix(CoxeterType(['H',4]).coxeter_graph()).coxeter_type() Coxeter type of ['H', 4] sage: CoxeterMatrix(CoxeterType(['I',100]).coxeter_graph()).coxeter_type() Coxeter type of ['I', 100] Some affine graphs:: sage: CoxeterMatrix(CoxeterType(['A',1,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 1, 1] sage: CoxeterMatrix(CoxeterType(['A',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['A', 10, 1] sage: CoxeterMatrix(CoxeterType(['B',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['B', 10, 1] sage: CoxeterMatrix(CoxeterType(['C',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['C', 10, 1] sage: CoxeterMatrix(CoxeterType(['D',10,1]).coxeter_graph()).coxeter_type() Coxeter type of ['D', 10, 1] sage: CoxeterMatrix(CoxeterType(['E',6,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 6, 1] sage: CoxeterMatrix(CoxeterType(['E',7,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 7, 1] sage: CoxeterMatrix(CoxeterType(['E',8,1]).coxeter_graph()).coxeter_type() Coxeter type of ['E', 8, 1] sage: CoxeterMatrix(CoxeterType(['F',4,1]).coxeter_graph()).coxeter_type() Coxeter type of ['F', 4, 1] sage: CoxeterMatrix(CoxeterType(['G',2,1]).coxeter_graph()).coxeter_type() Coxeter type of ['G', 2, 1] TESTS: Check that we detect relabellings:: sage: M = CoxeterMatrix([[1,2,3],[2,1,6],[3,6,1]], index_set=['a', 'b', 'c']) sage: M.coxeter_type() Coxeter type of ['G', 2, 1] relabelled by {0: 'a', 1: 'b', 2: 'c'} sage: from sage.combinat.root_system.coxeter_matrix import recognize_coxeter_type_from_matrix sage: for C in CoxeterMatrix.samples(): ....: relabelling_perm = Permutations(C.index_set()).random_element() ....: relabelling_dict = {C.index_set()[i]: relabelling_perm[i] for i in range(C.rank())} ....: relabeled_matrix = C.relabel(relabelling_dict)._matrix ....: recognized_type = recognize_coxeter_type_from_matrix(relabeled_matrix, relabelling_perm) ....: if C.is_finite() or C.is_affine(): ....: assert recognized_type == C.coxeter_type() We check the rank 2 cases (:trac:`20419`):: sage: for i in range(2, 10): ....: M = matrix([[1,i],[i,1]]) ....: CoxeterMatrix(M).coxeter_type() Coxeter type of A1xA1 relabelled by {1: 2} Coxeter type of ['A', 2] Coxeter type of ['B', 2] Coxeter type of ['I', 5] Coxeter type of ['G', 2] Coxeter type of ['I', 7] Coxeter type of ['I', 8] Coxeter type of ['I', 9] sage: CoxeterMatrix(matrix([[1,-1],[-1,1]]), index_set=[0,1]).coxeter_type() Coxeter type of ['A', 1, 1] """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) G = Graph( [ [index_set[i], index_set[j], coxeter_matrix[i, j]] for i in range(n) for j in range(i, n) if coxeter_matrix[i, j] not in [1, 2] ] ) G.add_vertices(index_set) types = [] for S in G.connected_components_subgraphs(): r = S.num_verts() # Handle the special cases first if r == 1: types.append(CoxeterType(["A", 1]).relabel({1: S.vertices()[0]})) continue if r == 2: # Type B2, G2, or I_2(p) e = S.edge_labels()[0] if e == 3: # Can't be 2 because it is connected ct = CoxeterType(["A", 2]) elif e == 4: ct = CoxeterType(["B", 2]) elif e == 6: ct = CoxeterType(["G", 2]) elif e > 0 and e < float("inf"): # Remaining non-affine types ct = CoxeterType(["I", e]) else: # Otherwise it is infinite dihedral group Z_2 \ast Z_2 ct = CoxeterType(["A", 1, 1]) if not ct.is_affine(): types.append(ct.relabel({1: S.vertices()[0], 2: S.vertices()[1]})) else: types.append(ct.relabel({0: S.vertices()[0], 1: S.vertices()[1]})) continue test = [["A", r], ["B", r], ["A", r - 1, 1]] if r >= 3: if r == 3: test += [["G", 2, 1], ["H", 3]] test.append(["C", r - 1, 1]) if r >= 4: if r == 4: test += [["F", 4], ["H", 4]] test += [["D", r], ["B", r - 1, 1]] if r >= 5: if r == 5: test.append(["F", 4, 1]) test.append(["D", r - 1, 1]) if r == 6: test.append(["E", 6]) elif r == 7: test += [["E", 7], ["E", 6, 1]] elif r == 8: test += [["E", 8], ["E", 7, 1]] elif r == 9: test.append(["E", 8, 1]) found = False for ct in test: ct = CoxeterType(ct) T = ct.coxeter_graph() iso, match = T.is_isomorphic(S, certify=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if not found: return None return CoxeterType(types)
def __classcall_private__( cls, data=None, index_set=None, coxeter_type=None, cartan_type=None, coxeter_type_check=True ): r""" A Coxeter matrix can we created via a graph, a Coxeter type, or a matrix. .. NOTE:: To disable the Coxeter type check, use the optional argument ``coxeter_type_check = False``. EXAMPLES:: sage: C = CoxeterMatrix(['A',1,1],['a','b']) sage: C2 = CoxeterMatrix([[1, -1], [-1, 1]]) sage: C3 = CoxeterMatrix(matrix([[1, -1], [-1, 1]]), [0, 1]) sage: C == C2 and C == C3 True Check with `\infty` because of the hack of using `-1` to represent `\infty` in the Coxeter matrix:: sage: G = Graph([(0, 1, 3), (1, 2, oo)]) sage: W1 = CoxeterMatrix([[1, 3, 2], [3, 1, -1], [2, -1, 1]]) sage: W2 = CoxeterMatrix(G) sage: W1 == W2 True sage: CoxeterMatrix(W1.coxeter_graph()) == W1 True The base ring of the matrix depends on the entries given:: sage: CoxeterMatrix([[1,-1],[-1,1]])._matrix.base_ring() Integer Ring sage: CoxeterMatrix([[1,-3/2],[-3/2,1]])._matrix.base_ring() Rational Field sage: CoxeterMatrix([[1,-1.5],[-1.5,1]])._matrix.base_ring() Real Field with 53 bits of precision """ if not data: if coxeter_type: data = CoxeterType(coxeter_type) elif cartan_type: data = CoxeterType(CartanType(cartan_type)) # Special cases with no arguments passed if not data: data = [] n = 0 index_set = tuple() coxeter_type = None base_ring = ZZ mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), data, coxeter_type, index_set) mat._subdivisions = None return mat if isinstance(data, CoxeterMatrix): # Initiate from itself return data # Initiate from a graph: # TODO: Check if a CoxeterDiagram once implemented if isinstance(data, Graph): return cls._from_graph(data, coxeter_type_check) # Get the Coxeter type coxeter_type = None from sage.combinat.root_system.cartan_type import CartanType_abstract if isinstance(data, CartanType_abstract): coxeter_type = data.coxeter_type() else: try: coxeter_type = CoxeterType(data) except (TypeError, ValueError, NotImplementedError): pass # Initiate from a Coxeter type if coxeter_type: return cls._from_coxetertype(coxeter_type) # TODO:: remove when oo is possible in matrices. n = len(data[0]) data = [x if x != infinity else -1 for r in data for x in r] data = matrix(n, n, data) # until here # Get the index set if index_set: index_set = tuple(index_set) else: index_set = tuple(range(1, n + 1)) if len(set(index_set)) != n: raise ValueError("the given index set is not valid") return cls._from_matrix(data, coxeter_type, index_set, coxeter_type_check)