class CartanTypeFindStat(object): """ A Cartan type class for FindStat """ def __init__(self, ct): self._cartan_type = CartanType(ct) def __hash__(self): return hash(self._cartan_type) def _latex_(self): return self._cartan_type.dynkin_diagram()._latex_() def __repr__(self): return self._cartan_type._repr_() _repr_ = __repr__
def DynkinDiagram(*args, **kwds): r""" Return the Dynkin diagram corresponding to the input. INPUT: The input can be one of the following: - empty to obtain an empty Dynkin diagram - a Cartan type - a Cartan matrix - a Cartan matrix and an indexing set Also one can input an index_set by The edge multiplicities are encoded as edge labels. This uses the convention in Hong and Kang, Kac, Fulton Harris, and crystals. This is the **opposite** convention in Bourbaki and Wikipedia's Dynkin diagram (:wikipedia:`Dynkin_diagram`). That is for `i \neq j`:: i <--k-- j <==> a_ij = -k <==> -scalar(coroot[i], root[j]) = k <==> multiple arrows point from the longer root to the shorter one For example, in type `C_2`, we have:: sage: C2 = DynkinDiagram(['C',2]); C2 O=<=O 1 2 C2 sage: C2.cartan_matrix() [ 2 -2] [-1 2] However Bourbaki would have the Cartan matrix as: .. MATH:: \begin{bmatrix} 2 & -1 \\ -2 & 2 \end{bmatrix}. EXAMPLES:: sage: DynkinDiagram(['A', 4]) O---O---O---O 1 2 3 4 A4 sage: DynkinDiagram(['A',1],['A',1]) O 1 O 2 A1xA1 sage: R = RootSystem("A2xB2xF4") sage: DynkinDiagram(R) O---O 1 2 O=>=O 3 4 O---O=>=O---O 5 6 7 8 A2xB2xF4 sage: R = RootSystem("A2xB2xF4") sage: CM = R.cartan_matrix(); CM [ 2 -1| 0 0| 0 0 0 0] [-1 2| 0 0| 0 0 0 0] [-----+-----+-----------] [ 0 0| 2 -1| 0 0 0 0] [ 0 0|-2 2| 0 0 0 0] [-----+-----+-----------] [ 0 0| 0 0| 2 -1 0 0] [ 0 0| 0 0|-1 2 -1 0] [ 0 0| 0 0| 0 -2 2 -1] [ 0 0| 0 0| 0 0 -1 2] sage: DD = DynkinDiagram(CM); DD O---O 1 2 O=>=O 3 4 O---O=>=O---O 5 6 7 8 A2xB2xF4 sage: DD.cartan_matrix() [ 2 -1 0 0 0 0 0 0] [-1 2 0 0 0 0 0 0] [ 0 0 2 -1 0 0 0 0] [ 0 0 -2 2 0 0 0 0] [ 0 0 0 0 2 -1 0 0] [ 0 0 0 0 -1 2 -1 0] [ 0 0 0 0 0 -2 2 -1] [ 0 0 0 0 0 0 -1 2] We can also create Dynkin diagrams from arbitrary Cartan matrices:: sage: C = CartanMatrix([[2, -3], [-4, 2]]) sage: DynkinDiagram(C) Dynkin diagram of rank 2 sage: C.index_set() (0, 1) sage: CI = CartanMatrix([[2, -3], [-4, 2]], [3, 5]) sage: DI = DynkinDiagram(CI) sage: DI.index_set() (3, 5) sage: CII = CartanMatrix([[2, -3], [-4, 2]]) sage: DII = DynkinDiagram(CII, ('y', 'x')) sage: DII.index_set() ('x', 'y') .. SEEALSO:: :func:`CartanType` for a general discussion on Cartan types and in particular node labeling conventions. TESTS: Check that :trac:`15277` is fixed by not having edges from 0's:: sage: CM = CartanMatrix([[2,-1,0,0],[-3,2,-2,-2],[0,-1,2,-1],[0,-1,-1,2]]) sage: CM [ 2 -1 0 0] [-3 2 -2 -2] [ 0 -1 2 -1] [ 0 -1 -1 2] sage: CM.dynkin_diagram().edges() [(0, 1, 3), (1, 0, 1), (1, 2, 1), (1, 3, 1), (2, 1, 2), (2, 3, 1), (3, 1, 2), (3, 2, 1)] """ if len(args) == 0: return DynkinDiagram_class() mat = args[0] if is_Matrix(mat): mat = CartanMatrix(*args) if isinstance(mat, CartanMatrix): if mat.cartan_type() is not mat: try: return mat.cartan_type().dynkin_diagram() except AttributeError: ct = CartanType(*args) raise ValueError( "Dynkin diagram data not yet hardcoded for type %s" % ct) if len(args) > 1: index_set = tuple(args[1]) elif "index_set" in kwds: index_set = tuple(kwds["index_set"]) else: index_set = mat.index_set() D = DynkinDiagram_class(index_set=index_set) for (i, j) in mat.nonzero_positions(): if i != j: D.add_edge(index_set[i], index_set[j], -mat[j, i]) return D ct = CartanType(*args) try: return ct.dynkin_diagram() except AttributeError: raise ValueError("Dynkin diagram data not yet hardcoded for type %s" % ct)
def find_cartan_type_from_matrix(CM): r""" Find a Cartan type by direct comparison of Dynkin diagrams given from the generalized Cartan matrix ``CM`` and return ``None`` if not found. INPUT: - ``CM`` -- a generalized Cartan matrix EXAMPLES:: sage: from sage.combinat.root_system.cartan_matrix import find_cartan_type_from_matrix sage: CM = CartanMatrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]]) sage: find_cartan_type_from_matrix(CM) ['A', 2, 1] sage: CM = CartanMatrix([[2,-1,0], [-1,2,-2], [0,-1,2]]) sage: find_cartan_type_from_matrix(CM) ['C', 3] relabelled by {1: 0, 2: 1, 3: 2} sage: CM = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) sage: find_cartan_type_from_matrix(CM) """ types = [] for S in CM.dynkin_diagram().connected_components_subgraphs(): S = DiGraph(S) # We need a simple digraph here n = S.num_verts() # Build the list to test based upon rank if n == 1: types.append(CartanType(['A', 1])) continue test = [['A', n]] if n >= 2: if n == 2: test += [['G', 2], ['A', 2, 2]] test += [['B', n], ['A', n - 1, 1]] if n >= 3: if n == 3: test.append(['G', 2, 1]) test += [['C', n], ['BC', n - 1, 2], ['C', n - 1, 1]] if n >= 4: if n == 4: test.append(['F', 4]) test += [['D', n], ['B', n - 1, 1]] if n >= 5: if n == 5: test.append(['F', 4, 1]) test.append(['D', n - 1, 1]) if n == 6: test.append(['E', 6]) elif n == 7: test += [['E', 7], ['E', 6, 1]] elif n == 8: test += [['E', 8], ['E', 7, 1]] elif n == 9: test.append(['E', 8, 1]) # Test every possible Cartan type and its dual found = False for x in test: ct = CartanType(x) T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if ct == ct.dual(): continue # self-dual, so nothing more to test ct = ct.dual() T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if not found: return None return CartanType(types)
def __classcall_private__(cls, data=None, index_set=None, cartan_type=None, cartan_type_check=True): """ Normalize input so we can inherit from sparse integer matrix. .. NOTE:: To disable the Cartan type check, use the optional argument ``cartan_type_check = False``. EXAMPLES:: sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) sage: C == C2 and C == C3 True TESTS: Check that :trac:`15740` is fixed:: sage: d = DynkinDiagram() sage: d.add_edge('a', 'b', 2) sage: d.index_set() ('a', 'b') sage: cm = CartanMatrix(d) sage: cm.index_set() ('a', 'b') """ # Special case with 0 args and kwds has Cartan type if cartan_type is not None and data is None: data = CartanType(cartan_type) if data is None: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None elif isinstance(data, CartanMatrix): if index_set is not None: d = {a: index_set[i] for i, a in enumerate(data.index_set())} return data.relabel(d) return data else: dynkin_diagram = None subdivisions = None from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class if isinstance(data, DynkinDiagram_class): dynkin_diagram = data cartan_type = data._cartan_type else: try: cartan_type = CartanType(data) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass if dynkin_diagram is not None: n = dynkin_diagram.rank() index_set = dynkin_diagram.index_set() oir = dynkin_diagram.odd_isotropic_roots() reverse = {a: i for i, a in enumerate(index_set)} data = {(i, i): 2 if index_set[i] not in oir else 0 for i in range(n)} for (i, j, l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(data) if not is_generalized_cartan_matrix(M): raise ValueError( "the input matrix is not a generalized Cartan matrix") n = M.ncols() data = M.dict() subdivisions = M._subdivisions if index_set is None: index_set = tuple(range(n)) else: index_set = tuple(index_set) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("the given index set is not valid") # We can do the Cartan type initialization later as this is not # a unique representation mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, False, True) # FIXME: We have to initialize the CartanMatrix part separately because # of the __cinit__ of the matrix. We should get rid of this workaround mat._CM_init(cartan_type, index_set, cartan_type_check) mat._subdivisions = subdivisions return mat
def __classcall_private__(cls, *args, **kwds): """ Normalize input so we can inherit from spare integer matrix. .. NOTE:: To disable the Cartan type check, use the optional argument ``cartan_type_check = False``. EXAMPLES:: sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) sage: C == C2 and C == C3 True """ # Special case with 0 args and kwds has cartan type if "cartan_type" in kwds and len(args) == 0: args = (CartanType(kwds["cartan_type"]),) if len(args) == 0: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) elif isinstance(args[0], CartanMatrix): return args[0] else: cartan_type = None dynkin_diagram = None subdivisions = None try: cartan_type = CartanType(args[0]) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass if dynkin_diagram is not None: n = cartan_type.rank() index_set = dynkin_diagram.index_set() reverse = dict((index_set[i], i) for i in range(len(index_set))) data = {(i, i): 2 for i in range(n)} for (i,j,l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(args[0]) if not is_generalized_cartan_matrix(M): raise ValueError("The input matrix is not a generalized Cartan matrix.") n = M.ncols() if "cartan_type" in kwds: cartan_type = CartanType(kwds["cartan_type"]) elif n == 1: cartan_type = CartanType(['A', 1]) elif kwds.get("cartan_type_check", True): cartan_type = find_cartan_type_from_matrix(M) data = M.dict() subdivisions = M._subdivisions if len(args) == 1: if cartan_type is not None: index_set = tuple(cartan_type.index_set()) else: index_set = tuple(range(M.ncols())) elif len(args) == 2: index_set = tuple(args[1]) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("The given index set is not valid.") else: raise ValueError("Too many arguments.") mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type, index_set) mat._subdivisions = subdivisions return mat
def DynkinDiagram(*args, **kwds): r""" Return the Dynkin diagram corresponding to the input. INPUT: The input can be one of the following: - empty to obtain an empty Dynkin diagram - a Cartan type - a Cartan matrix - a Cartan matrix and an indexing set One can also input an indexing set by passing a tuple using the optional argument ``index_set``. The edge multiplicities are encoded as edge labels. For the corresponding Cartan matrices, this uses the convention in Hong and Kang, Kac, Fulton and Harris, and crystals. This is the **opposite** convention in Bourbaki and Wikipedia's Dynkin diagram (:wikipedia:`Dynkin_diagram`). That is for `i \neq j`:: i <--k-- j <==> a_ij = -k <==> -scalar(coroot[i], root[j]) = k <==> multiple arrows point from the longer root to the shorter one For example, in type `C_2`, we have:: sage: C2 = DynkinDiagram(['C',2]); C2 O=<=O 1 2 C2 sage: C2.cartan_matrix() [ 2 -2] [-1 2] However Bourbaki would have the Cartan matrix as: .. MATH:: \begin{bmatrix} 2 & -1 \\ -2 & 2 \end{bmatrix}. EXAMPLES:: sage: DynkinDiagram(['A', 4]) O---O---O---O 1 2 3 4 A4 sage: DynkinDiagram(['A',1],['A',1]) O 1 O 2 A1xA1 sage: R = RootSystem("A2xB2xF4") sage: DynkinDiagram(R) O---O 1 2 O=>=O 3 4 O---O=>=O---O 5 6 7 8 A2xB2xF4 sage: R = RootSystem("A2xB2xF4") sage: CM = R.cartan_matrix(); CM [ 2 -1| 0 0| 0 0 0 0] [-1 2| 0 0| 0 0 0 0] [-----+-----+-----------] [ 0 0| 2 -1| 0 0 0 0] [ 0 0|-2 2| 0 0 0 0] [-----+-----+-----------] [ 0 0| 0 0| 2 -1 0 0] [ 0 0| 0 0|-1 2 -1 0] [ 0 0| 0 0| 0 -2 2 -1] [ 0 0| 0 0| 0 0 -1 2] sage: DD = DynkinDiagram(CM); DD O---O 1 2 O=>=O 3 4 O---O=>=O---O 5 6 7 8 A2xB2xF4 sage: DD.cartan_matrix() [ 2 -1 0 0 0 0 0 0] [-1 2 0 0 0 0 0 0] [ 0 0 2 -1 0 0 0 0] [ 0 0 -2 2 0 0 0 0] [ 0 0 0 0 2 -1 0 0] [ 0 0 0 0 -1 2 -1 0] [ 0 0 0 0 0 -2 2 -1] [ 0 0 0 0 0 0 -1 2] We can also create Dynkin diagrams from arbitrary Cartan matrices:: sage: C = CartanMatrix([[2, -3], [-4, 2]]) sage: DynkinDiagram(C) Dynkin diagram of rank 2 sage: C.index_set() (0, 1) sage: CI = CartanMatrix([[2, -3], [-4, 2]], [3, 5]) sage: DI = DynkinDiagram(CI) sage: DI.index_set() (3, 5) sage: CII = CartanMatrix([[2, -3], [-4, 2]]) sage: DII = DynkinDiagram(CII, ('y', 'x')) sage: DII.index_set() ('x', 'y') .. SEEALSO:: :func:`CartanType` for a general discussion on Cartan types and in particular node labeling conventions. TESTS: Check that :trac:`15277` is fixed by not having edges from 0's:: sage: CM = CartanMatrix([[2,-1,0,0],[-3,2,-2,-2],[0,-1,2,-1],[0,-1,-1,2]]) sage: CM [ 2 -1 0 0] [-3 2 -2 -2] [ 0 -1 2 -1] [ 0 -1 -1 2] sage: CM.dynkin_diagram().edges() [(0, 1, 3), (1, 0, 1), (1, 2, 1), (1, 3, 1), (2, 1, 2), (2, 3, 1), (3, 1, 2), (3, 2, 1)] """ if len(args) == 0: return DynkinDiagram_class() mat = args[0] if is_Matrix(mat): mat = CartanMatrix(*args) if isinstance(mat, CartanMatrix): if mat.cartan_type() is not mat: try: return mat.cartan_type().dynkin_diagram() except AttributeError: ct = CartanType(*args) raise ValueError("Dynkin diagram data not yet hardcoded for type %s"%ct) if len(args) > 1: index_set = tuple(args[1]) elif "index_set" in kwds: index_set = tuple(kwds["index_set"]) else: index_set = mat.index_set() D = DynkinDiagram_class(index_set=index_set) for (i, j) in mat.nonzero_positions(): if i != j: D.add_edge(index_set[i], index_set[j], -mat[j, i]) return D ct = CartanType(*args) try: return ct.dynkin_diagram() except AttributeError: raise ValueError("Dynkin diagram data not yet hardcoded for type %s"%ct)
def __classcall_private__(cls, *args, **kwds): """ Normalize input so we can inherit from spare integer matrix. .. NOTE:: To disable the Cartan type check, use the optional argument ``cartan_type_check = False``. EXAMPLES:: sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) sage: C == C2 and C == C3 True TESTS: Check that :trac:`15740` is fixed:: sage: d = DynkinDiagram() sage: d.add_edge('a', 'b', 2) sage: d.index_set() ('a', 'b') sage: cm = CartanMatrix(d) sage: cm.index_set() ('a', 'b') """ # Special case with 0 args and kwds has Cartan type if "cartan_type" in kwds and len(args) == 0: args = (CartanType(kwds["cartan_type"]),) if len(args) == 0: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None elif len(args) == 4 and isinstance(args[0], MatrixSpace): # For pickling return typecall(cls, args[0], args[1], args[2], args[3]) elif isinstance(args[0], CartanMatrix): return args[0] else: cartan_type = None dynkin_diagram = None subdivisions = None from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class if isinstance(args[0], DynkinDiagram_class): dynkin_diagram = args[0] cartan_type = args[0]._cartan_type else: try: cartan_type = CartanType(args[0]) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass if dynkin_diagram is not None: n = dynkin_diagram.rank() index_set = dynkin_diagram.index_set() reverse = dict((index_set[i], i) for i in range(len(index_set))) data = {(i, i): 2 for i in range(n)} for (i,j,l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(args[0]) if not is_generalized_cartan_matrix(M): raise ValueError("the input matrix is not a generalized Cartan matrix") n = M.ncols() if "cartan_type" in kwds: cartan_type = CartanType(kwds["cartan_type"]) elif n == 1: cartan_type = CartanType(['A', 1]) elif kwds.get("cartan_type_check", True): cartan_type = find_cartan_type_from_matrix(M) data = M.dict() subdivisions = M._subdivisions if len(args) == 1: if cartan_type is not None: index_set = tuple(cartan_type.index_set()) elif dynkin_diagram is None: index_set = tuple(range(n)) elif len(args) == 2: index_set = tuple(args[1]) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("the given index set is not valid") else: raise ValueError("too many arguments") mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, cartan_type, index_set) mat._subdivisions = subdivisions return mat
def __classcall_private__(cls, data=None, index_set=None, cartan_type=None, cartan_type_check=True, borcherds=None): """ Normalize input so we can inherit from sparse integer matrix. .. NOTE:: To disable the Cartan type check, use the optional argument ``cartan_type_check = False``. EXAMPLES:: sage: C = CartanMatrix(['A',1,1]) sage: C2 = CartanMatrix([[2, -2], [-2, 2]]) sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1]) sage: C == C2 and C == C3 True TESTS: Check that :trac:`15740` is fixed:: sage: d = DynkinDiagram() sage: d.add_edge('a', 'b', 2) sage: d.index_set() ('a', 'b') sage: cm = CartanMatrix(d) sage: cm.index_set() ('a', 'b') """ # Special case with 0 args and kwds has Cartan type if cartan_type is not None and data is None: data = CartanType(cartan_type) if data is None: data = [] n = 0 index_set = tuple() cartan_type = None subdivisions = None elif isinstance(data, CartanMatrix): if index_set is not None: d = {a: index_set[i] for i,a in enumerate(data.index_set())} return data.relabel(d) return data else: dynkin_diagram = None subdivisions = None from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class if isinstance(data, DynkinDiagram_class): dynkin_diagram = data cartan_type = data._cartan_type else: try: cartan_type = CartanType(data) dynkin_diagram = cartan_type.dynkin_diagram() except (TypeError, ValueError): pass if dynkin_diagram is not None: n = dynkin_diagram.rank() index_set = dynkin_diagram.index_set() oir = dynkin_diagram.odd_isotropic_roots() reverse = {a: i for i,a in enumerate(index_set)} if isinstance(borcherds, (list, tuple)): if (len(borcherds) != len(index_set) and not all(val in ZZ and (val == 2 or (val % 2 == 0 and val < 0)) for val in borcherds)): raise ValueError("the input data is not a Borcherds-Cartan matrix") data = {(i, i): val if index_set[i] not in oir else 0 for i,val in enumerate(borcherds)} else: data = {(i, i): 2 if index_set[i] not in oir else 0 for i in range(n)} for (i,j,l) in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(data) if borcherds: if not is_borcherds_cartan_matrix(M): raise ValueError("the input matrix is not a Borcherds-Cartan matrix") else: if not is_generalized_cartan_matrix(M): raise ValueError("the input matrix is not a generalized Cartan matrix") n = M.ncols() data = M.dict() subdivisions = M._subdivisions if index_set is None: index_set = tuple(range(n)) else: index_set = tuple(index_set) if len(index_set) != n and len(set(index_set)) != n: raise ValueError("the given index set is not valid") # We can do the Cartan type initialization later as this is not # a unique representation mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, False, True) # FIXME: We have to initialize the CartanMatrix part separately because # of the __cinit__ of the matrix. We should get rid of this workaround mat._CM_init(cartan_type, index_set, cartan_type_check) mat._subdivisions = subdivisions return mat
def find_cartan_type_from_matrix(CM): r""" Find a Cartan type by direct comparison of Dynkin diagrams given from the generalized Cartan matrix ``CM`` and return ``None`` if not found. INPUT: - ``CM`` -- a generalized Cartan matrix EXAMPLES:: sage: from sage.combinat.root_system.cartan_matrix import find_cartan_type_from_matrix sage: CM = CartanMatrix([[2,-1,-1], [-1,2,-1], [-1,-1,2]]) sage: find_cartan_type_from_matrix(CM) ['A', 2, 1] sage: CM = CartanMatrix([[2,-1,0], [-1,2,-2], [0,-1,2]]) sage: find_cartan_type_from_matrix(CM) ['C', 3] relabelled by {1: 0, 2: 1, 3: 2} sage: CM = CartanMatrix([[2,-1,-2], [-1,2,-1], [-2,-1,2]]) sage: find_cartan_type_from_matrix(CM) """ types = [] for S in CM.dynkin_diagram().connected_components_subgraphs(): S = DiGraph(S) # We need a simple digraph here n = S.num_verts() # Build the list to test based upon rank if n == 1: types.append(CartanType(['A', 1])) continue test = [['A', n]] if n >= 2: if n == 2: test += [['G',2], ['A',2,2]] test += [['B',n], ['A',n-1,1]] if n >= 3: if n == 3: test.append(['G',2,1]) test += [['C',n], ['BC',n-1,2], ['C',n-1,1]] if n >= 4: if n == 4: test.append(['F',4]) test += [['D',n], ['B',n-1,1]] if n >= 5: if n == 5: test.append(['F',4,1]) test.append(['D',n-1,1]) if n == 6: test.append(['E',6]) elif n == 7: test += [['E',7], ['E',6,1]] elif n == 8: test += [['E',8], ['E',7,1]] elif n == 9: test.append(['E',8,1]) # Test every possible Cartan type and its dual found = False for x in test: ct = CartanType(x) T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if ct == ct.dual(): continue # self-dual, so nothing more to test ct = ct.dual() T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True) if iso: types.append(ct.relabel(match)) found = True break if not found: return None return CartanType(types)