def cartan_matrix(self, subdivide=True): """ Return the Cartan matrix associated with ``self``. By default the Cartan matrix is a subdivided block matrix showing the reducibility but the subdivision can be suppressed with the option ``subdivide = False``. EXAMPLES:: sage: ct = CartanType("A2","B2") sage: ct.cartan_matrix() [ 2 -1| 0 0] [-1 2| 0 0] [-----+-----] [ 0 0| 2 -1] [ 0 0|-2 2] sage: ct.cartan_matrix(subdivide=False) [ 2 -1 0 0] [-1 2 0 0] [ 0 0 2 -1] [ 0 0 -2 2] """ from sage.combinat.root_system.cartan_matrix import CartanMatrix return CartanMatrix(block_diagonal_matrix( [t.cartan_matrix() for t in self._types], subdivide=subdivide), cartan_type=self)
def _Q_poly(self, a, m): r""" Return the element `Q^{(a)}_m` as a polynomial. We start with the relation .. MATH:: Q^{(a)}_{m-1}^2 = Q^{(a)}_m Q^{(a)}_{m-2} + \mathcal{Q}_{a,m-1}, which implies .. MATH:: Q^{(a)}_m = \frac{Q^{(a)}_{m-1}^2 - \mathcal{Q}_{a,m-1}}{ Q^{(a)}_{m-2}}. This becomes our relation used for reducing the Q-system to the fundamental representations. .. NOTE:: This helper method is defined in order to use the division implemented in polynomial rings. EXAMPLES:: sage: Q = QSystem(QQ, ['A',8]) sage: Q._Q_poly(1, 2) q1^2 - q2 sage: Q._Q_poly(3, 2) q3^2 - q2*q4 sage: Q._Q_poly(6, 3) q6^3 - 2*q5*q6*q7 + q4*q7^2 + q5^2*q8 - q4*q6*q8 """ if m == 0 or m == self._level: return self._poly.one() if m == 1: return self._poly.gen(self._cartan_type.index_set().index(a)) cm = CartanMatrix(self._cartan_type) I = self._cartan_type.index_set() m -= 1 # So we don't have to do it everywhere cur = self._Q_poly(a, m)**2 i = I.index(a) ret = self._poly.one() for b in self._cartan_type.dynkin_diagram().neighbors(a): j = I.index(b) for k in range(-cm[i, j]): ret *= self._Q_poly(b, (m * cm[j, i] - k) // cm[i, j]) cur -= ret if m > 1: cur //= self._Q_poly(a, m - 1) return cur
def cartan_matrix(self): r""" Returns the Cartan matrix for this Dynkin diagram EXAMPLES:: sage: DynkinDiagram(['C',3]).cartan_matrix() [ 2 -1 0] [-1 2 -2] [ 0 -1 2] """ return CartanMatrix(self)
def deformed_euler(self): """ Return the element `eu_k`. EXAMPLES:: sage: R = algebras.RationalCherednik(['A',2], 1, 1, QQ) sage: R.deformed_euler() 2*I + 2/3*a1*ac1 + 1/3*a1*ac2 + 1/3*a2*ac1 + 2/3*a2*ac2 + s1 + s2 + s1*s2*s1 """ I = self._cartan_type.index_set() G = self.algebra_generators() cm = ~CartanMatrix(self._cartan_type) n = len(I) ac = [G['ac' + str(i)] for i in I] la = [ sum(cm[i, j] * G['a' + str(I[i])] for i in range(n)) for j in range(n) ] return self.sum(ac[i] * la[i] for i in range(n))
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 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 WeylGroup(x, prefix=None, implementation='matrix'): """ Returns the Weyl group of the root system defined by the Cartan type (or matrix) ``ct``. INPUT: - ``x`` - a root system or a Cartan type (or matrix) OPTIONAL: - ``prefix`` -- changes the representation of elements from matrices to products of simple reflections - ``implementation`` -- one of the following: * ``'matrix'`` - as matrices acting on a root system * ``"permutation"`` - as a permutation group acting on the roots EXAMPLES: The following constructions yield the same result, namely a weight lattice and its corresponding Weyl group:: sage: G = WeylGroup(['F',4]) sage: L = G.domain() or alternatively and equivalently:: sage: L = RootSystem(['F',4]).ambient_space() sage: G = L.weyl_group() sage: W = WeylGroup(L) Either produces a weight lattice, with access to its roots and weights. :: sage: G = WeylGroup(['F',4]) sage: G.order() 1152 sage: [s1,s2,s3,s4] = G.simple_reflections() sage: w = s1*s2*s3*s4; w [ 1/2 1/2 1/2 1/2] [-1/2 1/2 1/2 -1/2] [ 1/2 1/2 -1/2 -1/2] [ 1/2 -1/2 1/2 -1/2] sage: type(w) == G.element_class True sage: w.order() 12 sage: w.length() # length function on Weyl group 4 The default representation of Weyl group elements is as matrices. If you prefer, you may specify a prefix, in which case the elements are represented as products of simple reflections. :: sage: W=WeylGroup("C3",prefix="s") sage: [s1,s2,s3]=W.simple_reflections() # lets Sage parse its own output sage: s2*s1*s2*s3 s1*s2*s3*s1 sage: s2*s1*s2*s3 == s1*s2*s3*s1 True sage: (s2*s3)^2==(s3*s2)^2 True sage: (s1*s2*s3*s1).matrix() [ 0 0 -1] [ 0 1 0] [ 1 0 0] :: sage: L = G.domain() sage: fw = L.fundamental_weights(); fw Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} sage: rho = sum(fw); rho (11/2, 5/2, 3/2, 1/2) sage: w.action(rho) # action of G on weight lattice (5, -1, 3, 2) We can also do the same for arbitrary Cartan matrices:: sage: cm = CartanMatrix([[2,-5,0],[-2,2,-1],[0,-1,2]]) sage: W = WeylGroup(cm) sage: W.gens() ( [-1 5 0] [ 1 0 0] [ 1 0 0] [ 0 1 0] [ 2 -1 1] [ 0 1 0] [ 0 0 1], [ 0 0 1], [ 0 1 -1] ) sage: s0,s1,s2 = W.gens() sage: s1*s2*s1 [ 1 0 0] [ 2 0 -1] [ 2 -1 0] sage: s2*s1*s2 [ 1 0 0] [ 2 0 -1] [ 2 -1 0] sage: s0*s1*s0*s2*s0 [ 9 0 -5] [ 2 0 -1] [ 0 1 -1] Same Cartan matrix, but with a prefix to display using simple reflections:: sage: W = WeylGroup(cm, prefix='s') sage: s0,s1,s2 = W.gens() sage: s0*s2*s1 s2*s0*s1 sage: (s1*s2)^3 1 sage: (s0*s1)^5 s0*s1*s0*s1*s0*s1*s0*s1*s0*s1 sage: s0*s1*s2*s1*s2 s2*s0*s1 sage: s0*s1*s2*s0*s2 s0*s1*s0 TESTS:: sage: TestSuite(WeylGroup(["A",3])).run() sage: TestSuite(WeylGroup(["A",3,1])).run() # long time sage: W = WeylGroup(['A',3,1]) sage: s = W.simple_reflections() sage: w = s[0]*s[1]*s[2] sage: w.reduced_word() [0, 1, 2] sage: w = s[0]*s[2] sage: w.reduced_word() [2, 0] sage: W = groups.misc.WeylGroup(['A',3,1]) """ if implementation == "permutation": return WeylGroup_permutation(x, prefix) elif implementation != "matrix": raise ValueError("invalid implementation") if x in RootLatticeRealizations: return WeylGroup_gens(x, prefix=prefix) try: ct = CartanType(x) except TypeError: ct = CartanMatrix(x) # See if it is a Cartan matrix if ct.is_finite(): return WeylGroup_gens(ct.root_system().ambient_space(), prefix=prefix) return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix)
def IntegralLattice(data, basis=None): r""" Return the integral lattice spanned by ``basis`` in the ambient space. A lattice is a finitely generated free abelian group `L \cong \ZZ^r` equipped with a non-degenerate, symmetric bilinear form `L \times L \colon \rightarrow \ZZ`. Here, lattices have an ambient quadratic space `\QQ^n` and a distinguished basis. INPUT: The input is a descriptor of the lattice and a (optional) basis. - ``data`` -- can be one of the following: * a symmetric matrix over the rationals -- the inner product matrix * an integer -- the dimension for an Euclidean lattice * a symmetric Cartan type or anything recognized by :class:`CartanMatrix` (see also :mod:`Cartan types <sage.combinat.root_system.cartan_type>`) -- for a root lattice * the string ``"U"`` or ``"H"`` -- for hyperbolic lattices - ``basis`` -- (optional) a matrix whose rows form a basis of the lattice, or a list of module elements forming a basis OUTPUT: A lattice in the ambient space defined by the inner_product_matrix. Unless specified, the basis of the lattice is the standard basis. EXAMPLES:: sage: H5 = Matrix(ZZ, 2, [2,1,1,-2]) sage: IntegralLattice(H5) Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: [1 0] [0 1] Inner product matrix: [ 2 1] [ 1 -2] A basis can be specified too:: sage: IntegralLattice(H5, Matrix([1,1])) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] Inner product matrix: [ 2 1] [ 1 -2] We can define an Euclidean lattice just by its dimension:: sage: IntegralLattice(3) Lattice of degree 3 and rank 3 over Integer Ring Basis matrix: [1 0 0] [0 1 0] [0 0 1] Inner product matrix: [1 0 0] [0 1 0] [0 0 1] Here is an example of the `A_2` root lattice in Euclidean space:: sage: basis = Matrix([[1,-1,0], [0,1,-1]]) sage: A2 = IntegralLattice(3, basis) sage: A2 Lattice of degree 3 and rank 2 over Integer Ring Basis matrix: [ 1 -1 0] [ 0 1 -1] Inner product matrix: [1 0 0] [0 1 0] [0 0 1] sage: A2.gram_matrix() [ 2 -1] [-1 2] We use ``"U"`` or ``"H"`` for defining a hyperbolic lattice:: sage: L1 = IntegralLattice("U") sage: L1 Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: [1 0] [0 1] Inner product matrix: [0 1] [1 0] sage: L1 == IntegralLattice("H") True We can construct root lattices by specifying their type (see :mod:`Cartan types <sage.combinat.root_system.cartan_type>` and :class:`CartanMatrix`):: sage: IntegralLattice(["E", 7]) Lattice of degree 7 and rank 7 over Integer Ring Basis matrix: [1 0 0 0 0 0 0] [0 1 0 0 0 0 0] [0 0 1 0 0 0 0] [0 0 0 1 0 0 0] [0 0 0 0 1 0 0] [0 0 0 0 0 1 0] [0 0 0 0 0 0 1] Inner product matrix: [ 2 0 -1 0 0 0 0] [ 0 2 0 -1 0 0 0] [-1 0 2 -1 0 0 0] [ 0 -1 -1 2 -1 0 0] [ 0 0 0 -1 2 -1 0] [ 0 0 0 0 -1 2 -1] [ 0 0 0 0 0 -1 2] sage: IntegralLattice(["A", 2]) Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: [1 0] [0 1] Inner product matrix: [ 2 -1] [-1 2] sage: IntegralLattice("D3") Lattice of degree 3 and rank 3 over Integer Ring Basis matrix: [1 0 0] [0 1 0] [0 0 1] Inner product matrix: [ 2 -1 -1] [-1 2 0] [-1 0 2] sage: IntegralLattice(["D", 4]) Lattice of degree 4 and rank 4 over Integer Ring Basis matrix: [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] Inner product matrix: [ 2 -1 0 0] [-1 2 -1 -1] [ 0 -1 2 0] [ 0 -1 0 2] We can specify a basis as well:: sage: G = Matrix(ZZ, 2, [0,1,1,0]) sage: B = [vector([1,1])] sage: IntegralLattice(G, basis=B) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] Inner product matrix: [0 1] [1 0] sage: IntegralLattice(["A", 3], [[1,1,1]]) Lattice of degree 3 and rank 1 over Integer Ring Basis matrix: [1 1 1] Inner product matrix: [ 2 -1 0] [-1 2 -1] [ 0 -1 2] sage: IntegralLattice(4, [[1,1,1,1]]) Lattice of degree 4 and rank 1 over Integer Ring Basis matrix: [1 1 1 1] Inner product matrix: [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] sage: IntegralLattice("A2", [[1,1]]) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] Inner product matrix: [ 2 -1] [-1 2] TESTS:: sage: IntegralLattice(["A", 1, 1]) Traceback (most recent call last): ... ValueError: lattices must be nondegenerate; use FreeQuadraticModule instead sage: IntegralLattice(["D", 3, 1]) Traceback (most recent call last): ... ValueError: lattices must be nondegenerate; use FreeQuadraticModule instead """ if is_Matrix(data): inner_product_matrix = data elif isinstance(data, Integer): inner_product_matrix = matrix.identity(ZZ, data) elif data == "U" or data == "H": inner_product_matrix = matrix([[0, 1], [1, 0]]) else: inner_product_matrix = CartanMatrix(data) if basis is None: basis = matrix.identity(ZZ, inner_product_matrix.ncols()) if inner_product_matrix != inner_product_matrix.transpose(): raise ValueError("the inner product matrix must be symmetric\n%s" % inner_product_matrix) A = FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix) return FreeQuadraticModule_integer_symmetric( ambient=A, basis=basis, inner_product_matrix=A.inner_product_matrix(), already_echelonized=False)
def IntegralLattice(data, basis=None): r""" Return the integral lattice spanned by ``basis`` in the ambient space. A lattice is a finitely generated free abelian group `L \cong \ZZ^r` equipped with a non-degenerate, symmetric bilinear form `L \times L \colon \rightarrow \ZZ`. Here, lattices have an ambient quadratic space `\QQ^n` and a distinguished basis. INPUT: The input is a descriptor of the lattice and a (optional) basis. - ``data`` -- can be one of the following: * a symmetric matrix over the rationals -- the inner product matrix * an integer -- the dimension for a euclidian lattice * a symmetric Cartan type or anything recognized by :class:`CartanMatrix` (see also :mod:`Cartan types <sage.combinat.root_system.cartan_type>`) -- for a root lattice * the string ``"U"`` or ``"H"`` -- for hyperbolic lattices - ``basis`` -- (optional) a matrix whose rows form a basis of the lattice, or a list of module elements forming a basis OUTPUT: A lattice in the ambient space defined by the inner_product_matrix. Unless specified, the basis of the lattice is the standard basis. EXAMPLES:: sage: H5 = Matrix(ZZ, 2, [2,1,1,-2]) sage: IntegralLattice(H5) Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: [1 0] [0 1] Inner product matrix: [ 2 1] [ 1 -2] A basis can be specified too:: sage: IntegralLattice(H5, Matrix([1,1])) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] Inner product matrix: [ 2 1] [ 1 -2] We can define a Euclidian lattice just by its dimension:: sage: IntegralLattice(3) Lattice of degree 3 and rank 3 over Integer Ring Basis matrix: [1 0 0] [0 1 0] [0 0 1] Inner product matrix: [1 0 0] [0 1 0] [0 0 1] Here is an example of the `A_2` root lattice in Euclidian space:: sage: basis = Matrix([[1,-1,0], [0,1,-1]]) sage: A2 = IntegralLattice(3, basis) sage: A2 Lattice of degree 3 and rank 2 over Integer Ring Basis matrix: [ 1 -1 0] [ 0 1 -1] Inner product matrix: [1 0 0] [0 1 0] [0 0 1] sage: A2.gram_matrix() [ 2 -1] [-1 2] We use ``"U"`` or ``"H"`` for defining a hyperbolic lattice:: sage: L1 = IntegralLattice("U") sage: L1 Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: [1 0] [0 1] Inner product matrix: [0 1] [1 0] sage: L1 == IntegralLattice("H") True We can construct root lattices by specifying their type (see :mod:`Cartan types <sage.combinat.root_system.cartan_type>` and :class:`CartanMatrix`):: sage: IntegralLattice(["E", 7]) Lattice of degree 7 and rank 7 over Integer Ring Basis matrix: [1 0 0 0 0 0 0] [0 1 0 0 0 0 0] [0 0 1 0 0 0 0] [0 0 0 1 0 0 0] [0 0 0 0 1 0 0] [0 0 0 0 0 1 0] [0 0 0 0 0 0 1] Inner product matrix: [ 2 0 -1 0 0 0 0] [ 0 2 0 -1 0 0 0] [-1 0 2 -1 0 0 0] [ 0 -1 -1 2 -1 0 0] [ 0 0 0 -1 2 -1 0] [ 0 0 0 0 -1 2 -1] [ 0 0 0 0 0 -1 2] sage: IntegralLattice(["A", 2]) Lattice of degree 2 and rank 2 over Integer Ring Basis matrix: [1 0] [0 1] Inner product matrix: [ 2 -1] [-1 2] sage: IntegralLattice("D3") Lattice of degree 3 and rank 3 over Integer Ring Basis matrix: [1 0 0] [0 1 0] [0 0 1] Inner product matrix: [ 2 -1 -1] [-1 2 0] [-1 0 2] sage: IntegralLattice(["D", 4]) Lattice of degree 4 and rank 4 over Integer Ring Basis matrix: [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] Inner product matrix: [ 2 -1 0 0] [-1 2 -1 -1] [ 0 -1 2 0] [ 0 -1 0 2] We can specify a basis as well:: sage: G = Matrix(ZZ, 2, [0,1,1,0]) sage: B = [vector([1,1])] sage: IntegralLattice(G, basis=B) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] Inner product matrix: [0 1] [1 0] sage: IntegralLattice(["A", 3], [[1,1,1]]) Lattice of degree 3 and rank 1 over Integer Ring Basis matrix: [1 1 1] Inner product matrix: [ 2 -1 0] [-1 2 -1] [ 0 -1 2] sage: IntegralLattice(4, [[1,1,1,1]]) Lattice of degree 4 and rank 1 over Integer Ring Basis matrix: [1 1 1 1] Inner product matrix: [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] sage: IntegralLattice("A2", [[1,1]]) Lattice of degree 2 and rank 1 over Integer Ring Basis matrix: [1 1] Inner product matrix: [ 2 -1] [-1 2] TESTS:: sage: IntegralLattice(["A", 1, 1]) Traceback (most recent call last): ... ValueError: lattices must be nondegenerate; use FreeQuadraticModule instead sage: IntegralLattice(["D", 3, 1]) Traceback (most recent call last): ... ValueError: lattices must be nondegenerate; use FreeQuadraticModule instead """ if is_Matrix(data): inner_product_matrix = data elif isinstance(data, Integer): inner_product_matrix = matrix.identity(ZZ, data) elif data == "U" or data == "H": inner_product_matrix = matrix([[0,1],[1,0]]) else: inner_product_matrix = CartanMatrix(data) if basis is None: basis = matrix.identity(ZZ, inner_product_matrix.ncols()) if inner_product_matrix != inner_product_matrix.transpose(): raise ValueError("the inner product matrix must be symmetric\n%s" % inner_product_matrix) A = FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix) return FreeQuadraticModule_integer_symmetric(ambient=A, basis=basis, inner_product_matrix=A.inner_product_matrix(), already_echelonized=False)
def cartan_companion(self): return CartanMatrix(2 - matrix(self.rk, map(abs, self.B0.list())))