def __init__(self, R, names, index_set, **kwds): """ Initialize ``self``. EXAMPLES:: sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) sage: TestSuite(L).run() """ LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, index_set, **kwds)
def __init__(self, R, names, index_set, category, **kwds): """ Initialize ``self``. EXAMPLES:: sage: L = LieAlgebra(QQ, 3, 'x', abelian=True) sage: TestSuite(L).run() """ cat = LieAlgebras(R).FiniteDimensional().WithBasis().Nilpotent() category = cat.or_subcategory(category) LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, index_set, category, **kwds)
def __init__(self, R, s_coeff, names, index_set, step=None, **kwds): r""" Initialize ``self``. EXAMPLES:: sage: L.<X,Y,Z,W> = LieAlgebra(QQ, {('X','Y'): {'Z': 1}}, nilpotent=True) sage: TestSuite(L).run() """ if step is not None: self._step = step LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeff, names, index_set, **kwds)
def __classcall_private__(cls, R, classification, s_coeff, names, index_set=None, category=None, **kwds): r""" Normalize input to ensure a unique representation. """ names, index_set = standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) cat = LieAlgebras(R).FiniteDimensional().WithBasis().Nilpotent() category = cat.or_subcategory(category) return super(ClassifiedNilpotentLieAlgebra, cls).__classcall__(cls, R, classification, s_coeff, names, index_set, category=category, **kwds)
def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, category=None, **kwds): """ Normalize input to ensure a unique representation. EXAMPLES: If the variable order is specified, the order of structural coefficients does not matter:: sage: from sage.algebras.lie_algebras.nilpotent_lie_algebra import NilpotentLieAlgebra_dense sage: L1.<x,y,z> = NilpotentLieAlgebra_dense(QQ, {('x','y'): {'z': 1}}) sage: L2.<x,y,z> = NilpotentLieAlgebra_dense(QQ, {('y','x'): {'z': -1}}) sage: L1 is L2 True If the variables are implicitly defined by the structural coefficients, the ordering may be different and the Lie algebras will be considered different:: sage: from sage.algebras.lie_algebras.nilpotent_lie_algebra import NilpotentLieAlgebra_dense sage: L1 = NilpotentLieAlgebra_dense(QQ, {('x','y'): {'z': 1}}) sage: L2 = NilpotentLieAlgebra_dense(QQ, {('y','x'): {'z': -1}}) sage: L1 Nilpotent Lie algebra on 3 generators (x, y, z) over Rational Field sage: L2 Nilpotent Lie algebra on 3 generators (y, x, z) over Rational Field sage: L1 is L2 False Constructed using two different methods from :class:`LieAlgebra` yields the same Lie algebra:: sage: sc = {('X','Y'): {'Z': 1}} sage: C = LieAlgebras(QQ).Nilpotent().FiniteDimensional().WithBasis() sage: L1.<X,Y,Z> = LieAlgebra(QQ, sc, category=C) sage: L2 = LieAlgebra(QQ, sc, nilpotent=True, names=['X','Y','Z']) sage: L1 is L2 True """ if not names: # extract names from structural coefficients names = [] for (X, Y), d in s_coeff.items(): if X not in names: names.append(X) if Y not in names: names.append(Y) for k in d: if k not in names: names.append(k) from sage.structure.indexed_generators import standardize_names_index_set names, index_set = standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) cat = LieAlgebras(R).FiniteDimensional().WithBasis().Nilpotent() category = cat.or_subcategory(category) return super(NilpotentLieAlgebra_dense, cls).__classcall__( cls, R, s_coeff, names, index_set, category=category, **kwds)
def __init__(self, I, L, names, index_set, category=None): r""" Initialize ``self``. TESTS:: sage: L.<x,y,z> = LieAlgebra(SR, {('x','y'): {'x':1}}) sage: K = L.quotient(y) sage: K.dimension() 1 sage: TestSuite(K).run() """ B = L.basis() sm = L.module().submodule_with_basis( [I.reduce(B[i]).to_vector() for i in index_set]) SB = sm.basis() # compute and normalize structural coefficients for the quotient s_coeff = {} for i, ind_i in enumerate(index_set): for j in range(i + 1, len(index_set)): ind_j = index_set[j] brkt = I.reduce(L.bracket(SB[i], SB[j])) brktvec = sm.coordinate_vector(brkt.to_vector()) s_coeff[(ind_i, ind_j)] = dict(zip(index_set, brktvec)) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) self._ambient = L self._I = I self._sm = sm LieAlgebraWithStructureCoefficients.__init__(self, L.base_ring(), s_coeff, names, index_set, category=category) # register the quotient morphism as a conversion H = Hom(L, self) f = SetMorphism(H, self.retract) self.register_conversion(f)
def __init__(self, I, L, names, index_set, category=None): r""" Initialize ``self``. TESTS:: sage: L.<x,y,z> = LieAlgebra(SR, {('x','y'): {'x':1}}) sage: K = L.quotient(y) sage: K.dimension() 1 sage: TestSuite(K).run() """ B = L.basis() sm = L.module().submodule_with_basis([I.reduce(B[i]).to_vector() for i in index_set]) SB = sm.basis() # compute and normalize structural coefficients for the quotient s_coeff = {} for i, ind_i in enumerate(index_set): for j in range(i + 1, len(index_set)): ind_j = index_set[j] brkt = I.reduce(L.bracket(SB[i], SB[j])) brktvec = sm.coordinate_vector(brkt.to_vector()) s_coeff[(ind_i, ind_j)] = dict(zip(index_set, brktvec)) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) self._ambient = L self._I = I self._sm = sm LieAlgebraWithStructureCoefficients.__init__( self, L.base_ring(), s_coeff, names, index_set, category=category) # register the quotient morphism as a conversion H = Hom(L, self) f = SetMorphism(H, self.retract) self.register_conversion(f)
def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): """ The Lie algebra of affine transformations of the line. EXAMPLES:: sage: L = lie_algebras.affine_transformations_line(QQ) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y} sage: X, Y = L.lie_algebra_generators() sage: L[X, Y] == Y True sage: TestSuite(L).run() sage: L = lie_algebras.affine_transformations_line(QQ, representation="matrix") sage: X, Y = L.lie_algebra_generators() sage: L[X, Y] == Y True sage: TestSuite(L).run() """ if isinstance(names, str): names = names.split(',') names = tuple(names) if representation == 'matrix': from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(R, 2, sparse=True) one = R.one() gens = tuple(MS({(0, i): one}) for i in range(2)) from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative return LieAlgebraFromAssociative(MS, gens, names=names) X = names[0] Y = names[1] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients s_coeff = {(X, Y): {Y: R.one()}} L = LieAlgebraWithStructureCoefficients(R, s_coeff, names=names) L.rename( "Lie algebra of affine transformations of a line over {}".format(R)) return L
def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): """ The Lie algebra of affine transformations of the line. EXAMPLES:: sage: L = lie_algebras.affine_transformations_line(QQ) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y} sage: X, Y = L.lie_algebra_generators() sage: L[X, Y] == Y True sage: TestSuite(L).run() sage: L = lie_algebras.affine_transformations_line(QQ, representation="matrix") sage: X, Y = L.lie_algebra_generators() sage: L[X, Y] == Y True sage: TestSuite(L).run() """ if isinstance(names, str): names = names.split(',') names = tuple(names) if representation == 'matrix': from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(R, 2, sparse=True) one = R.one() gens = tuple(MS({(0,i):one}) for i in range(2)) from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative return LieAlgebraFromAssociative(MS, gens, names=names) X = names[0] Y = names[1] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients s_coeff = {(X,Y): {Y:R.one()}} L = LieAlgebraWithStructureCoefficients(R, s_coeff, names=names) L.rename("Lie algebra of affine transformations of a line over {}".format(R)) return L
def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): r""" The 3-dimensional Lie algebra over a given commutative ring `R` with basis `\{X, Y, Z\}` subject to the relations: .. MATH:: [X, Y] = aZ + dY, \quad [Y, Z] = bX, \quad [Z, X] = cY + dZ where `a,b,c,d \in R`. This is always a well-defined 3-dimensional Lie algebra, as can be easily proven by computation. EXAMPLES:: sage: L = lie_algebras.three_dimensional(QQ, 4, 1, -1, 2) sage: L.structure_coefficients() Finite family {('X', 'Y'): 2*Y + 4*Z, ('X', 'Z'): Y - 2*Z, ('Y', 'Z'): X} sage: TestSuite(L).run() sage: L = lie_algebras.three_dimensional(QQ, 1, 0, 0, 0) sage: L.structure_coefficients() Finite family {('X', 'Y'): Z} sage: L = lie_algebras.three_dimensional(QQ, 0, 0, -1, -1) sage: L.structure_coefficients() Finite family {('X', 'Y'): -Y, ('X', 'Z'): Y + Z} sage: L = lie_algebras.three_dimensional(QQ, 0, 1, 0, 0) sage: L.structure_coefficients() Finite family {('Y', 'Z'): X} sage: lie_algebras.three_dimensional(QQ, 0, 0, 0, 0) Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field sage: Q.<a,b,c,d> = PolynomialRing(QQ) sage: L = lie_algebras.three_dimensional(Q, a, b, c, d) sage: L.structure_coefficients() Finite family {('X', 'Y'): d*Y + a*Z, ('X', 'Z'): (-c)*Y + (-d)*Z, ('Y', 'Z'): b*X} sage: TestSuite(L).run() """ if isinstance(names, str): names = names.split(',') X = names[0] Y = names[1] Z = names[2] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients s_coeff = {(X,Y): {Z:a, Y:d}, (Y,Z): {X:b}, (Z,X): {Y:c, Z:d}} return LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names))
def _symbolic_lie_algebra_copy(L): r""" Create a copy of the Lie algebra ``L`` admitting symbolic coefficients. This is used internally to compute a symbolic expression for the group law. INPUT: - ``L`` -- a finite dimensional Lie algebra with basis EXAMPLES:: sage: from sage.groups.lie_gps.nilpotent_lie_group import _symbolic_lie_algebra_copy sage: L = LieAlgebra(QQ, 2, step=2) sage: L_SR = _symbolic_lie_algebra_copy(L) sage: L.structure_coefficients() Finite family {((1,), (2,)): X_12} sage: L_SR.structure_coefficients() Finite family {((1,), (2,)): L[(1, 2)]} TESTS: Verify that copying works with something that is not an instance of :class:`LieAlgebraWithStructureCoefficients`:: sage: from sage.groups.lie_gps.nilpotent_lie_group import _symbolic_lie_algebra_copy sage: L = lie_algebras.Heisenberg(QQ, 1) sage: hasattr(L, 'change_ring') False sage: L_SR = _symbolic_lie_algebra_copy(L) sage: L_SR.structure_coefficients() Finite family {('p1', 'q1'): z} """ try: return L.change_ring(SR) except AttributeError: s_coeff = L.structure_coefficients() index_set = L.basis().keys() names = L.variable_names() return LieAlgebraWithStructureCoefficients(SR, s_coeff, names=names, index_set=index_set)
def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, category=None, **kwds): """ Normalize input to ensure a unique representation. EXAMPLES: If the variable order is specified, the order of structural coefficients does not matter:: sage: from sage.algebras.lie_algebras.nilpotent_lie_algebra import NilpotentLieAlgebra_dense sage: L1.<x,y,z> = NilpotentLieAlgebra_dense(QQ, {('x','y'): {'z': 1}}) sage: L2.<x,y,z> = NilpotentLieAlgebra_dense(QQ, {('y','x'): {'z': -1}}) sage: L1 is L2 True If the variables are implicitly defined by the structural coefficients, the ordering may be different and the Lie algebras will be considered different:: sage: from sage.algebras.lie_algebras.nilpotent_lie_algebra import NilpotentLieAlgebra_dense sage: L1 = NilpotentLieAlgebra_dense(QQ, {('x','y'): {'z': 1}}) sage: L2 = NilpotentLieAlgebra_dense(QQ, {('y','x'): {'z': -1}}) sage: L1 Nilpotent Lie algebra on 3 generators (x, y, z) over Rational Field sage: L2 Nilpotent Lie algebra on 3 generators (y, x, z) over Rational Field sage: L1 is L2 False Constructed using two different methods from :class:`LieAlgebra` yields the same Lie algebra:: sage: sc = {('X','Y'): {'Z': 1}} sage: C = LieAlgebras(QQ).Nilpotent().FiniteDimensional().WithBasis() sage: L1.<X,Y,Z> = LieAlgebra(QQ, sc, category=C) sage: L2 = LieAlgebra(QQ, sc, nilpotent=True, names=['X','Y','Z']) sage: L1 is L2 True """ if not names: # extract names from structural coefficients names = [] for (X, Y), d in s_coeff.items(): if X not in names: names.append(X) if Y not in names: names.append(Y) for k in d: if k not in names: names.append(k) from sage.structure.indexed_generators import standardize_names_index_set names, index_set = standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) cat = LieAlgebras(R).FiniteDimensional().WithBasis().Nilpotent() category = cat.or_subcategory(category) return super(NilpotentLieAlgebra_dense, cls).__classcall__(cls, R, s_coeff, names, index_set, category=category, **kwds)
def __init__(self, R, r, s, names, naming, category, **kwds): r""" Initialize ``self`` EXAMPLES:: sage: L = LieAlgebra(ZZ, 2, step=2) sage: TestSuite(L).run() sage: L = LieAlgebra(QQ, 4, step=3) sage: TestSuite(L).run() # long time """ if r not in ZZ or r <= 0: raise ValueError("number of generators %s is not " "a positive integer" % r) if s not in ZZ or s <= 0: raise ValueError("step %s is not a positive integer" % s) # extract an index set from the Lyndon words of the corresponding # free Lie algebra, and store the corresponding elements in a dict from sage.algebras.lie_algebras.lie_algebra import LieAlgebra free_gen_names = ['F%d' % k for k in range(r)] free_gen_names_inv = { val: i + 1 for i, val in enumerate(free_gen_names) } L = LieAlgebra(R, free_gen_names).Lyndon() basis_by_deg = {d: [] for d in range(1, s + 1)} for d in range(1, s + 1): for X in L.graded_basis(d): # convert brackets of form [X_1, [X_1, X_2]] to words (1,1,2) w = tuple(free_gen_names_inv[s] for s in X.leading_support().to_word()) basis_by_deg[d].append((w, X)) index_set = [ind for d in basis_by_deg for ind, val in basis_by_deg[d]] if len(names) == 1 and len(index_set) > 1: if not naming: if r >= 10: naming = 'linear' else: naming = 'index' if naming == 'linear': names = [ '%s_%d' % (names[0], k + 1) for k in range(len(index_set)) ] elif naming == 'index': if r >= 10: raise ValueError("'index' naming scheme not supported for " "10 or more generators") names = [ '%s_%s' % (names[0], "".join(str(s) for s in ind)) for ind in index_set ] else: raise ValueError("unknown naming scheme %s" % naming) # extract structural coefficients from the free Lie algebra s_coeff = {} for dx in range(1, s + 1): # Brackets are only computed when deg(X) + deg(Y) <= s # We also require deg(Y) >= deg(X) by the ordering for dy in range(dx, s + 1 - dx): if dx == dy: for i, val in enumerate(basis_by_deg[dx]): X_ind, X = val for Y_ind, Y in basis_by_deg[dy][i + 1:]: Z = L[X, Y] if not Z.is_zero(): s_coeff[(X_ind, Y_ind)] = { W_ind: Z[W.leading_support()] for W_ind, W in basis_by_deg[dx + dy] } else: for X_ind, X in basis_by_deg[dx]: for Y_ind, Y in basis_by_deg[dy]: Z = L[X, Y] if not Z.is_zero(): s_coeff[(X_ind, Y_ind)] = { W_ind: Z[W.leading_support()] for W_ind, W in basis_by_deg[dx + dy] } names, index_set = standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) NilpotentLieAlgebra_dense.__init__(self, R, s_coeff, names, index_set, s, category=category, **kwds)
def __init__(self, R, cartan_type): r""" Initialize ``self``. TESTS:: sage: L = LieAlgebra(QQ, cartan_type=['A',2]) sage: TestSuite(L).run() # long time """ self._cartan_type = cartan_type RL = cartan_type.root_system().root_lattice() alpha = RL.simple_roots() p_roots = list(RL.positive_roots_by_height()) n_roots = [-x for x in p_roots] self._p_roots_index = {al: i for i,al in enumerate(p_roots)} alphacheck = RL.simple_coroots() roots = frozenset(RL.roots()) num_sroots = len(alpha) one = R.one() # Determine the signs for the structure coefficients from the root system # We first create the special roots sp_sign = {} for i,a in enumerate(p_roots): for b in p_roots[i+1:]: if a + b not in p_roots: continue # Compute the sign for the extra special pair x, y = (a + b).extraspecial_pair() if (x, y) == (a, b): # If it already is an extra special pair if (x, y) not in sp_sign: # This swap is so the structure coefficients match with GAP if (sum(x.coefficients()) == sum(y.coefficients()) and str(x) > str(y)): y,x = x,y sp_sign[(x, y)] = -one sp_sign[(y, x)] = one continue if b - x in roots: t1 = ((b-x).norm_squared() / b.norm_squared() * sp_sign[(x, b-x)] * sp_sign[(a, y-a)]) else: t1 = 0 if a - x in roots: t2 = ((a-x).norm_squared() / a.norm_squared() * sp_sign[(x, a-x)] * sp_sign[(b, y-b)]) else: t2 = 0 if t1 - t2 > 0: sp_sign[(a,b)] = -one elif t2 - t1 > 0: sp_sign[(a,b)] = one sp_sign[(b,a)] = -sp_sign[(a,b)] # Function to construct the structure coefficients (up to sign) def e_coeff(r, s): p = 1 while r - p*s in roots: p += 1 return p # Now we can compute all necessary structure coefficients s_coeffs = {} for i,r in enumerate(p_roots): # [e_r, h_i] and [h_i, f_r] for ac in alphacheck: c = r.scalar(ac) if c == 0: continue s_coeffs[(r, ac)] = {r: -c} s_coeffs[(ac, -r)] = {-r: -c} # [e_r, f_r] s_coeffs[(r, -r)] = {alphacheck[j]: c for j, c in r.associated_coroot()} # [e_r, e_s] and [e_r, f_s] with r != +/-s # We assume s is positive, as otherwise we negate # both r and s and the resulting coefficient for j, s in enumerate(p_roots[i+1:]): j += i+1 # Offset # Since h(s) >= h(r), we have s - r > 0 when s - r is a root # [f_r, e_s] if s - r in p_roots: c = e_coeff(r, -s) a, b = s-r, r if self._p_roots_index[a] > self._p_roots_index[b]: # Note a != b c *= -sp_sign[(b, a)] else: c *= sp_sign[(a, b)] s_coeffs[(-r, s)] = {a: -c} s_coeffs[(r, -s)] = {-a: c} # [e_r, e_s] a = r + s if a in p_roots: # (r, s) is a special pair c = e_coeff(r, s) * sp_sign[(r, s)] s_coeffs[(r, s)] = {a: c} s_coeffs[(-r, -s)] = {-a: -c} # Lastly, make sure a < b for all (a, b) in the coefficients and flip if necessary for k in s_coeffs.keys(): a,b = k[0], k[1] if self._basis_key(a) > self._basis_key(b): s_coeffs[(b,a)] = [(index, -v) for index,v in s_coeffs[k].items()] del s_coeffs[k] else: s_coeffs[k] = s_coeffs[k].items() names = ['e{}'.format(i) for i in range(1, num_sroots+1)] names += ['f{}'.format(i) for i in range(1, num_sroots+1)] names += ['h{}'.format(i) for i in range(1, num_sroots+1)] category = LieAlgebras(R).FiniteDimensional().WithBasis() index_set = p_roots + list(alphacheck) + n_roots names = tuple(names) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet index_set = FiniteEnumeratedSet(index_set) LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeffs, names, index_set, category, prefix='E', bracket='[', sorting_key=self._basis_key)
def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): """ Return a 3-dimensional Lie algebra of rank ``n``, where `0 \leq n \leq 3`. Here, the *rank* of a Lie algebra `L` is defined as the dimension of its derived subalgebra `[L, L]`. (We are assuming that `R` is a field of characteristic `0`; otherwise the Lie algebras constructed by this function are still well-defined but no longer might have the correct ranks.) This is not to be confused with the other standard definition of a rank (namely, as the dimension of a Cartan subalgebra, when `L` is semisimple). INPUT: - ``R`` -- the base ring - ``n`` -- the rank - ``a`` -- the deformation parameter (used for `n = 2`); this should be a nonzero element of `R` in order for the resulting Lie algebra to actually have the right rank(?) - ``names`` -- (optional) the generator names EXAMPLES:: sage: lie_algebras.three_dimensional_by_rank(QQ, 0) Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field sage: L = lie_algebras.three_dimensional_by_rank(QQ, 1) sage: L.structure_coefficients() Finite family {('Y', 'Z'): X} sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 4) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y, ('X', 'Z'): Y + Z} sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 0) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y} sage: lie_algebras.three_dimensional_by_rank(QQ, 3) sl2 over Rational Field """ if isinstance(names, str): names = names.split(',') names = tuple(names) if n == 0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names=names) if n == 1: L = three_dimensional(R, 0, 1, 0, 0, names=names) # Strictly upper triangular matrices L.rename("Lie algebra of 3x3 strictly upper triangular matrices over {}".format(R)) return L if n == 2: if a is None: raise ValueError("The parameter 'a' must be specified") X = names[0] Y = names[1] Z = names[2] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients if a == 0: s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R(a)}} # Why use R(a) here if R == 0 ? Also this has rank 1. L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Degenerate Lie algebra of dimension 3 and rank 2 over {}".format(R)) else: s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R.one(), Z:R.one()}} # a doesn't appear here :/ L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) return L if n == 3: #return sl(R, 2) from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients E = names[0] F = names[1] H = names[2] s_coeff = { (E,F): {H:R.one()}, (H,E): {E:R(2)}, (H,F): {F:R(-2)} } L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("sl2 over {}".format(R)) return L raise ValueError("Invalid rank")
def __init__(self, R, r, s, names, naming, category, **kwds): r""" Initialize ``self`` EXAMPLES:: sage: L = LieAlgebra(ZZ, 2, step=2) sage: TestSuite(L).run() sage: L = LieAlgebra(QQ, 4, step=3) sage: TestSuite(L).run() # long time """ if r not in ZZ or r <= 0: raise ValueError("number of generators %s is not " "a positive integer" % r) if s not in ZZ or s <= 0: raise ValueError("step %s is not a positive integer" % s) # extract an index set from the Lyndon words of the corresponding # free Lie algebra, and store the corresponding elements in a dict from sage.algebras.lie_algebras.lie_algebra import LieAlgebra free_gen_names = ['F%d' % k for k in range(r)] free_gen_names_inv = {val: i + 1 for i, val in enumerate(free_gen_names)} L = LieAlgebra(R, free_gen_names).Lyndon() basis_by_deg = {d: [] for d in range(1, s + 1)} for d in range(1, s + 1): for X in L.graded_basis(d): # convert brackets of form [X_1, [X_1, X_2]] to words (1,1,2) w = tuple(free_gen_names_inv[s] for s in X.leading_support().to_word()) basis_by_deg[d].append((w, X)) index_set = [ind for d in basis_by_deg for ind, val in basis_by_deg[d]] if len(names) == 1 and len(index_set) > 1: if not naming: if r >= 10: naming = 'linear' else: naming = 'index' if naming == 'linear': names = ['%s_%d' % (names[0], k + 1) for k in range(len(index_set))] elif naming == 'index': if r >= 10: raise ValueError("'index' naming scheme not supported for " "10 or more generators") names = ['%s_%s' % (names[0], "".join(str(s) for s in w)) for w in index_set] else: raise ValueError("unknown naming scheme %s" % naming) # extract structural coefficients from the free Lie algebra s_coeff = {} for dx in range(1, s + 1): # Brackets are only computed when deg(X) + deg(Y) <= s # We also require deg(Y) >= deg(X) by the ordering for dy in range(dx, s + 1 - dx): if dx == dy: for i, val in enumerate(basis_by_deg[dx]): X_ind, X = val for Y_ind, Y in basis_by_deg[dy][i + 1:]: Z = L[X, Y] if not Z.is_zero(): s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] for W_ind, W in basis_by_deg[dx + dy]} else: for X_ind, X in basis_by_deg[dx]: for Y_ind, Y in basis_by_deg[dy]: Z = L[X, Y] if not Z.is_zero(): s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] for W_ind, W in basis_by_deg[dx + dy]} names, index_set = standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) NilpotentLieAlgebra_dense.__init__(self, R, s_coeff, names, index_set, s, category=category, **kwds)
def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): r""" Return a 3-dimensional Lie algebra of rank ``n``, where `0 \leq n \leq 3`. Here, the *rank* of a Lie algebra `L` is defined as the dimension of its derived subalgebra `[L, L]`. (We are assuming that `R` is a field of characteristic `0`; otherwise the Lie algebras constructed by this function are still well-defined but no longer might have the correct ranks.) This is not to be confused with the other standard definition of a rank (namely, as the dimension of a Cartan subalgebra, when `L` is semisimple). INPUT: - ``R`` -- the base ring - ``n`` -- the rank - ``a`` -- the deformation parameter (used for `n = 2`); this should be a nonzero element of `R` in order for the resulting Lie algebra to actually have the right rank(?) - ``names`` -- (optional) the generator names EXAMPLES:: sage: lie_algebras.three_dimensional_by_rank(QQ, 0) Abelian Lie algebra on 3 generators (X, Y, Z) over Rational Field sage: L = lie_algebras.three_dimensional_by_rank(QQ, 1) sage: L.structure_coefficients() Finite family {('Y', 'Z'): X} sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 4) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y, ('X', 'Z'): Y + Z} sage: L = lie_algebras.three_dimensional_by_rank(QQ, 2, 0) sage: L.structure_coefficients() Finite family {('X', 'Y'): Y} sage: lie_algebras.three_dimensional_by_rank(QQ, 3) sl2 over Rational Field """ if isinstance(names, str): names = names.split(',') names = tuple(names) if n == 0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names=names) if n == 1: L = three_dimensional(R, 0, 1, 0, 0, names=names) # Strictly upper triangular matrices L.rename("Lie algebra of 3x3 strictly upper triangular matrices over {}".format(R)) return L if n == 2: if a is None: raise ValueError("The parameter 'a' must be specified") X = names[0] Y = names[1] Z = names[2] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients if a == 0: s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R(a)}} # Why use R(a) here if R == 0 ? Also this has rank 1. L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Degenerate Lie algebra of dimension 3 and rank 2 over {}".format(R)) else: s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R.one(), Z:R.one()}} # a doesn't appear here :/ L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) return L if n == 3: #return sl(R, 2) from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients E = names[0] F = names[1] H = names[2] s_coeff = { (E,F): {H:R.one()}, (H,E): {E:R(2)}, (H,F): {F:R(-2)} } L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("sl2 over {}".format(R)) return L raise ValueError("Invalid rank")
def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, index_set=None, abelian=False, **kwds): """ Select the correct parent based upon input. TESTS:: sage: LieAlgebra(QQ, abelian=True, names='x,y,z') Abelian Lie algebra on 3 generators (x, y, z) over Rational Field sage: LieAlgebra(QQ, {('e','h'): {'e':-2}, ('f','h'): {'f':2}, ....: ('e','f'): {'h':1}}, names='e,f,h') Lie algebra on 3 generators (e, f, h) over Rational Field """ # Parse associative algebra input # ----- assoc = kwds.get("associative", None) if assoc is not None: return LieAlgebraFromAssociative(assoc, names=names, index_set=index_set) # Parse input as a Cartan type # ----- ct = kwds.get("cartan_type", None) if ct is not None: from sage.combinat.root_system.cartan_type import CartanType ct = CartanType(ct) if ct.is_affine(): from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra return AffineLieAlgebra(R, cartan_type=ct, kac_moody=kwds.get("kac_moody", True)) if not ct.is_finite(): raise NotImplementedError( "non-finite types are not implemented yet, see trac #14901 for details" ) rep = kwds.get("representation", "bracket") if rep == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis return LieAlgebraChevalleyBasis(R, ct) if rep == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import ClassicalMatrixLieAlgebra return ClassicalMatrixLieAlgebra(R, ct) raise ValueError("invalid representation") # Parse the remaining arguments # ----- if R is None: raise ValueError("invalid arguments") check_assoc = lambda A: (isinstance(A, (Ring, MatrixSpace)) or A in Rings() or A in Algebras(R).Associative()) if arg0 in ZZ or check_assoc(arg1): # Check if we need to swap the arguments arg0, arg1 = arg1, arg0 # Parse the first argument # ----- if isinstance(arg0, dict): if not arg0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) elif isinstance(next(iter(arg0.keys())), (list, tuple)): # We assume it is some structure coefficients arg1, arg0 = arg0, arg1 if isinstance(arg0, (list, tuple)): if all(isinstance(x, str) for x in arg0): # If they are all strings, then it is a list of variables names = tuple(arg0) if isinstance(arg0, str): names = tuple(arg0.split(',')) elif isinstance(names, str): names = tuple(names.split(',')) # Parse the second argument if isinstance(arg1, dict): # Assume it is some structure coefficients from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, **kwds) # Otherwise it must be either a free or abelian Lie algebra if arg1 in ZZ: if isinstance(arg0, str): names = arg0 if names is None: index_set = list(range(arg1)) else: if isinstance(names, str): names = tuple(names.split(',')) if arg1 != 1 and len(names) == 1: names = tuple('{}{}'.format(names[0], i) for i in range(arg1)) if arg1 != len(names): raise ValueError("the number of names must equal the" " number of generators") if abelian: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra return AbelianLieAlgebra(R, names, index_set) # Otherwise it is the free Lie algebra rep = kwds.get("representation", "bracket") if rep == "polynomial": # Construct the free Lie algebra from polynomials in the # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one from sage.algebras.free_algebra import FreeAlgebra F = FreeAlgebra(R, names) if index_set is None: index_set = F.variable_names() # TODO: As part of #16823, this should instead construct a # subclass with specialized methods for the free Lie algebra return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set) raise NotImplementedError("the free Lie algebra has only been" " implemented using polynomials in the" " free algebra, see trac ticket #16823")