# Ticket #6670: trac-6670-group_algebra-6.patch

File trac-6670-group_algebra-6.patch, 24.9 KB (added by Martin Raum, 12 years ago)
• ## sage/algebras/all.py

# HG changeset patch
# User Martin Raum <Martin.Raum@matha.rwth-aachen.de>
# Date 1300841480 -3600
# Node ID 5c8212195c95db9eac1e006b72741a3f9c2cd582
# Parent  eb9456d5aff3d8725a2e9919d77f5c6654e4bb6f
#6670: Port group algebras to the current coercion system

diff -r eb9456d5aff3 -r 5c8212195c95 sage/algebras/all.py
 a from steenrod_algebra_element import Sq from steenrod_algebra_bases import steenrod_algebra_basis from group_algebra import GroupAlgebra, GroupAlgebraElement from group_algebra_new import GroupAlgebra, GroupAlgebraElement from iwahori_hecke_algebra import IwahoriHeckeAlgebraT from affine_nil_temperley_lieb import AffineNilTemperleyLiebTypeA
• ## new file sage/algebras/group_algebra_new.py

diff -r eb9456d5aff3 -r 5c8212195c95 sage/algebras/group_algebra_new.py
 - r""" Group algebra of a group This module provides functionality for constructing and working with group algebras of arbitrary groups (over a general commutative base ring). .. note:: It seems to be difficult to make this fit nicely with Sage's coercion model. The problem is that (for example) if G is the additive group (\ZZ,+), and R = \ZZ[G] is its group ring, then the integer 2 can be coerced into R in two ways -- via G, or via the base ring -- and *the answers are different*. In practice we get around this by preventing elements of G coercing automatically into \ZZ[G], which is a shame, but makes more sense than preventing elements of the base ring doing so. AUTHOR: - David Loeffler (2008-08-24): initial version - Martin Raum (2009-08): update to use new coercion model """ #***************************************************************************** #       Copyright (C) 2009 Martin Raum #                     2008 William Stein #                     2008 David Loeffler # #  Distributed under the terms of the GNU General Public License (GPL) #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.categories.all import GroupAlgebras from sage.structure.parent_gens import ParentWithGens from sage.algebras.algebra import Algebra from sage.algebras.algebra_element import AlgebraElement from sage.rings.all import IntegerRing from sage.groups.group import Group from sage.structure.formal_sum import FormalSums, FormalSum from sage.structure.element import Element from sage.sets.set import Set from sage.misc.latex import latex from sage.categories.morphism import Morphism from sage.categories.pushout import ConstructionFunctor from sage.categories.rings import Rings _cache = dict() class GroupAlgebraFunctor ( ConstructionFunctor ) : r""" A functor assigning a group algebra to its base ring. """ def __init__(self, group) : r""" INPUT : - group -- a group that will be the module basis for the group algebras in the range. EXAMPLES:: sage: from sage.algebras.group_algebra import GroupAlgebraFunctor sage: F = GroupAlgebraFunctor(KleinFourGroup()) sage: loads(dumps(F)) == F True sage: GroupAlgebra(SU(2, GF(4, 'a')), IntegerModRing(12)).category() Category of group algebras over Ring of integers modulo 12 """ self.__group = group ConstructionFunctor.__init__(self, Rings(), Rings()) def group(self) : r""" Return the group which is associtated to this functor. EXAMPLES:: sage: from sage.algebras.group_algebra import GroupAlgebraFunctor sage: GroupAlgebraFunctor(CyclicPermutationGroup(17)).group() == CyclicPermutationGroup(17) True """ return self.__group def __call__(self, base_ring) : r""" Create the group algeba with given base ring over self.group(). INPUT : - base_ring - the base ring of the group algebra. OUTPUT: A group algebra. EXAMPLES:: sage: from sage.algebras.group_algebra import GroupAlgebraFunctor sage: F = GroupAlgebraFunctor(CyclicPermutationGroup(17)) sage: F(QQ) Group algebra of group "Cyclic group of order 17 as a permutation group" over base ring Rational Field """ return GroupAlgebra(self.__group, base_ring) def GroupAlgebra(group, base_ring = IntegerRing()) : r""" Create the given group algebra. INPUT:: - (Group) group: a generic group. - (Ring) base_ring: a commutative ring. OUTPUT: - a GroupAlgebra instance. EXAMPLES:: sage: GroupAlgebra(GL(3, GF(7))) Group algebra of group "General Linear Group of degree 3 over Finite Field of size 7" over base ring Integer Ring sage: GroupAlgebra(1) Traceback (most recent call last): ... TypeError: "1" is not a group sage: GroupAlgebra(KleinFourGroup()) is GroupAlgebra(KleinFourGroup()) True """ global _cache if not base_ring.is_commutative(): raise NotImplementedError, "Base ring must be commutative" if not isinstance(group, Group): raise TypeError, '"%s" is not a group' % group key = (group, base_ring) try : return _cache[key] except KeyError : A = GroupAlgebra_class(group, base_ring) _cache[key] = A return A class GroupAlgebra_class ( Algebra ) : def __init__(self, group, base_ring): r""" Create the given group algebra. INPUT: -- (Group) group: a generic group. -- (Ring) base_ring: a commutative ring. OUTPUT: -- a GroupAlgebra instance. EXAMPLES:: sage: GroupAlgebra(GL(3, GF(7))) Group algebra of group "General Linear Group of degree 3 over Finite Field of size 7" over base ring Integer Ring sage: GroupAlgebra(1) Traceback (most recent call last): ... TypeError: "1" is not a group sage: GroupAlgebra(SU(2, GF(4, 'a')), IntegerModRing(12)).category() Category of group algebras over Ring of integers modulo 12 TESTS:: sage: A = GroupAlgebra(GL(3, GF(7))) sage: A.has_coerce_map_from(GL(3, GF(7))) True sage: G = SymmetricGroup(5) sage: x,y = G.gens() sage: A = GroupAlgebra(G) sage: A( A(x) ) """ if not base_ring.is_commutative(): raise NotImplementedError, "Base ring must be commutative" if not isinstance(group, Group): raise TypeError, '"%s" is not a group' % group ParentWithGens.__init__(self, base_ring, category = GroupAlgebras(base_ring)) self._formal_sum_module = FormalSums(base_ring) self._group = group if not base_ring.has_coerce_map_from(group) : ## some matrix groups assume that coercion is only valid to ## other matrix groups. This is a workaround ## call _element_constructor_ to coerce group elements #try : self._populate_coercion_lists_( coerce_list = [base_ring, group] ) #except TypeError : #    self._populate_coercion_lists_( coerce_list = [base_ring] ) else : self._populate_coercion_lists_( coerce_list = [base_ring] ) def ngens(self) : r""" Return the number of generators. EXAMPLES:: sage: A = GroupAlgebra(SL2Z) sage: A.ngens() 2 """ return self._group.ngens() def gen(self, i = 0) : r""" EXAMPLES:: sage: A = GroupAlgebra(GL(3, GF(7))) sage: A.gen(0) [3 0 0] [0 1 0] [0 0 1] """ return self._element_constructor(self._group.gen(i), as_group_element = True) def group(self): r""" Return the group of this group algebra. EXAMPLES:: sage: GroupAlgebra(GL(3, GF(11))).group() General Linear Group of degree 3 over Finite Field of size 11 sage: GroupAlgebra(SymmetricGroup(10)).group() Symmetric group of order 10! as a permutation group """ return self._group ########################################################################### ## GroupAlgebra_class :: mathmatical properties ########################################################################### def is_commutative(self): r""" Return True if self is a commutative ring. True if and only if self.group() is abelian. EXAMPLES:: sage: GroupAlgebra(SymmetricGroup(2)).is_commutative() True sage: GroupAlgebra(SymmetricGroup(3)).is_commutative() False """ return self.group().is_abelian() def is_field(self, proof = True): r""" Return True if self is a field. This is always false unless self.group() is trivial and self.base_ring() is a field. EXAMPLES:: sage: GroupAlgebra(SymmetricGroup(2)).is_field() False sage: GroupAlgebra(SymmetricGroup(1)).is_field() False sage: GroupAlgebra(SymmetricGroup(1), QQ).is_field() True """ if not self.base_ring().is_field(proof): return False return (self.group().order() == 1) def is_finite(self): r""" Return True if self is finite, which is true if and only if self.group() and self.base_ring() are both finite. EXAMPLES:: sage: GroupAlgebra(SymmetricGroup(2), IntegerModRing(10)).is_finite() True sage: GroupAlgebra(SymmetricGroup(2)).is_finite() False sage: GroupAlgebra(AbelianGroup(1), IntegerModRing(10)).is_finite() False """ return (self.base_ring().is_finite() and self.group().is_finite()) def is_exact(self): r""" Return True if elements of self have exact representations, which is true of self if and only if it is true of self.group() and self.base_ring(). EXAMPLES:: sage: GroupAlgebra(GL(3, GF(7))).is_exact() True sage: GroupAlgebra(GL(3, GF(7)), RR).is_exact() False sage: GroupAlgebra(GL(3, pAdicRing(7))).is_exact() # not implemented correctly (not my fault)! False """ return self.group().is_exact() and self.base_ring().is_exact() def is_integral_domain(self, proof = True): r""" Return True if self is an integral domain. This is false unless self.base_ring() is an integral domain, and even then it is false unless self.group() has no nontrivial elements of finite order. I don't know if this condition suffices, but it obviously does if the group is abelian and finitely generated. EXAMPLES:: sage: GroupAlgebra(SymmetricGroup(2)).is_integral_domain() False sage: GroupAlgebra(SymmetricGroup(1)).is_integral_domain() True sage: GroupAlgebra(SymmetricGroup(1), IntegerModRing(4)).is_integral_domain() False sage: GroupAlgebra(AbelianGroup(1)).is_integral_domain() True sage: GroupAlgebra(AbelianGroup(2, [0,2])).is_integral_domain() False sage: GroupAlgebra(GL(2, ZZ)).is_integral_domain() # not implemented False """ ans = False try: if self.base_ring().is_integral_domain(): if self.group().is_finite(): if self.group().order() > 1: ans = False else: ans = True else: if self.group().is_abelian(): invs = self.group().invariants() if Set(invs) != Set([0]): ans = False else: ans = True else: raise NotImplementedError else: ans = False except AttributeError: if proof: raise NotImplementedError, "cannot determine whether self is an integral domain" except NotImplementedError: if proof: raise NotImplementedError, "cannot determine whether self is an integral domain" return ans # I haven't written is_noetherian(), because I don't know when group # algebras are noetherian, and I haven't written is_prime_field(), because # I don't know if that means "is canonically isomorphic to a prime field" # or "is identical to a prime field". ########################################################################### ## GroupAlgebra_class :: elements ########################################################################### def _an_element_(self): r""" Return an element of self. EXAMPLES:: sage: A = GroupAlgebra(GL(3, GF(7))) sage: A.an_element() [3 0 0] [0 1 0] [0 0 1] """ return self(self._formal_sum_module([ (self.base_ring().an_element(), self.group().an_element()) ])) def random_element(self) : r""" Return a random element of self. EXAMPLE:: sage: GroupAlgebra(SU(2, 13), QQ).an_element() # random; hideous formatting! -1/95*[       9 2*a + 12] [       0        3] - 4*[      9 9*a + 2] [3*a + 5       1] """ return self(self._formal_sum_module([ (self.base_ring().random_element(), self.group().random_element()), (self.base_ring().random_element(), self.group().random_element()), ])) def construction(self) : r""" EXAMPLES:: sage: A = GroupAlgebra(KleinFourGroup(), QQ) sage: A.construction() (GroupAlgebraFunctor, Rational Field) """ return GroupAlgebraFunctor(self._group), self.base_ring() def _element_constructor_(self, x, as_group_element = False) : r""" Create an element of this group algebra. INPUT: - x: either a FormalSum element consisting of elements of self.group(), an element of self.base_ring(), or an element of self.group(). - as_group_element: if true and x may be considered as a basis element and a group element, consider it a group element OUTPUT: - a GroupAlgebraElement instance whose parent is self. EXAMPLES:: sage: G = KleinFourGroup() sage: f = G.gen(0) sage: ZG = GroupAlgebra(G) sage: ZG(f) (3,4) sage: ZG(1) == ZG(G(1)) True sage: G = AbelianGroup(1) sage: ZG = GroupAlgebra(G) sage: f = ZG.group().gen() sage: ZG(FormalSum([(1,f), (2, f**2)])) f + 2*f^2 sage: G = GL(2,7) sage: OG = GroupAlgebra(G, ZZ[sqrt(5)]) sage: OG(2) 2*[1 0] [0 1] sage: OG(G(2)) # conversion is not the obvious one [2 0] [0 2] sage: OG(FormalSum([ (1, G(2)), (2, RR(0.77)) ]) ) Traceback (most recent call last): ... TypeError: Cannot coerce 0.770000000000000 to a 2-by-2 matrix over Finite Field of size 7 Ordering of elements in output unpredictable as sort order of such wildly dissimilar elements is subject to change between platforms and versions (see trac ticket \#4373). :: sage: OG(OG.base_ring().gens()[1]) sqrt5*[1 0] [0 1] """ if isinstance(x, Element) : P = x.parent() if P is self.base_ring() and not as_group_element: return GroupAlgebraElement_class(self, self._formal_sum_module( [(x, self.group()(1))] ) ) elif P is self.group() : return GroupAlgebraElement_class(self, self._formal_sum_module( [(self.base_ring().one_element(), x)] ) ) elif P is self._formal_sum_module : return GroupAlgebraElement_class(self, x) elif isinstance(x, FormalSum) and self._formal_sum_module.has_coerce_map_from(P) : return GroupAlgebraElement_class(self, self._formal_sum_module( [(self.base_ring()(c), self.group()(g)) for c,g in x] ) ) raise TypeError, "Don't know how to create an element of %s from %s" % \ (self, x) def __cmp__(self, other) : r""" Compare two algebras self and other. They are considered equal if and only if their base rings and their groups coincide. EXAMPLES:: sage: GroupAlgebra(AbelianGroup(1)) == GroupAlgebra(AbelianGroup(1)) True sage: GroupAlgebra(AbelianGroup(1), QQ) == GroupAlgebra(AbelianGroup(1), ZZ) False sage: GroupAlgebra(AbelianGroup(2)) == GroupAlgebra(AbelianGroup(1)) False sage: from sage.algebras.group_algebra import GroupAlgebra_class sage: A = GroupAlgebra_class(KleinFourGroup(), ZZ) sage: B = GroupAlgebra_class(KleinFourGroup(), QQ) sage: A == B False sage: A == A True """ c = cmp(type(self), type(other)) if c == 0 : c = cmp(self._group, other._group) if c == 0 : c = cmp(self.base_ring(), other.base_ring()) return c def _repr_(self): r""" String representation of self. See GroupAlgebra.__init__ for a doctest. EXAMPLES:: sage: A = GroupAlgebra(KleinFourGroup(), ZZ) sage: A Group algebra of group "The Klein 4 group of order 4, as a permutation group" over base ring Integer Ring """ return "Group algebra of group \"%s\" over base ring %s" % \ (self.group(), self.base_ring()) def _latex_(self): r"""Latex string of self. EXAMPLES:: sage: A = GroupAlgebra(KleinFourGroup(), ZZ) sage: latex(A) Group algebra of group \langle (3,4), (1,2) \rangle over base ring \Bold{Z} """ return "Group algebra of group %s over base ring %s" % \ (latex(self.group()), latex(self.base_ring())) def element_class(self): r""" The class of elements of self, which is GroupAlgebraElement. EXAMPLES:: sage: GroupAlgebra(SU(2, GF(4,'a'))).element_class() """ return GroupAlgebraElement_class def GroupAlgebraElement(parent, x, check = True) : r""" Create an element of the group algebra parent. - x -- an element of the base ring, the group or a formal sum with summand (a, g), where a is in the base ring and g is in the group - check -- determines whether the summand of a formal sum will be checked for correctness EXAMPLES:: sage: G = KleinFourGroup() sage: A = GroupAlgebra(G) sage: GroupAlgebraElement(A, A.group().gen(1)) (1,2) sage: GroupAlgebraElement(A, 1) () sage: GroupAlgebraElement(A, 10) 10*() """ ## Provide this for backward compatibility to the old class layout assert isinstance(parent, GroupAlgebra_class), "%s must be group algebra" if not isinstance(x, Element) : x = IntegerRing()(x) if isinstance(x, FormalSum) and check : for c,g in x : if not c in parent.base_ring() or not g in parent.group() : raise ValueError, "summands of %s must be elements of base " + \ "ring and group respectively" return parent._element_constructor(x) ########################################################################### ## GroupAlgebraElement_class ########################################################################### class GroupAlgebraElement_class ( AlgebraElement ) : def __init__(self, parent, x): r""" Create an element of the parent group algebra. Not intended to be called by the user; see GroupAlgebra._element_constructor_ for examples and doctests. EXAMPLES:: sage: A = GroupAlgebra(KleinFourGroup(), ZZ) sage: GroupAlgebraElement(A, A._formal_sum_module([(1, KleinFourGroup().gen(0))])) (3,4) """ AlgebraElement.__init__(self, parent) self._fs = x ########################################################################### ## GroupAlgebraElement_class :: Arithmetic ########################################################################### def _add_(left, right): r""" Add left to right. EXAMPLE:: sage: G = GL(3, GF(7)) sage: ZG = GroupAlgebra(G) sage: g1 = ZG.group()([0,0,2,2,5,0,6,6,2]) sage: s = ZG(g1) sage: s + s 2*[0  0  2] [2  5  0] [6  6  2] """ return left.parent()(left._fs + right._fs) def _mul_(left, right): r""" Calculate left*right, where both left and right are GroupAlgebraElements_class. EXAMPLE:: sage: G = GL(3, GF(7)) sage: ZG = GroupAlgebra(G) sage: a, b = G.random_element(), G.random_element() sage: za, zb = ZG(a), ZG(b) sage: za*ZG(2) # random 2*[4,5,0] [0,5,1] [2,5,1] sage: za*2 == za*ZG(2) True sage: (ZG(1) + za)*(ZG(2) + zb) == ZG(FormalSum([ (2,G(1)), (2,a), (1, b), (1, a*b)])) True sage: za*za == za^2 True """ if left.parent().group().is_multiplicative() : product = [ (a1 * a2, g1 * g2) for (a1,g1) in left._fs for (a2,g2) in right._fs ] else : product = [ (a1 * a2, g1 + g2) for (a1,g1) in left._fs for (a2,g2) in right._fs ] return left.parent()( left.parent()._formal_sum_module(product) ) ########################################################################### ## GroupAlgebraElement_class :: Comparision ########################################################################### def __cmp__(self, other) : r""" Compare self and other. EXAMPLES:: sage: G = AbelianGroup(1,[4]) sage: ZG = GroupAlgebra(G) sage: a = ZG(1) sage: b = ZG(2) sage: a + a == b True sage: a == b False sage: a == GroupAlgebra(AbelianGroup(1, [5]))(1) False """ c = cmp(type(self), type(other)) if c == 0 : c = cmp(self._fs, other._fs) return c ########################################################################### ## GroupAlgebraElement_class :: Representations ########################################################################### def _repr_(self) : r""" EXAMPLES:: sage: G = KleinFourGroup() sage: A = GroupAlgebra(G, ZZ) sage: latex(A(1) + A(A.group().gen(0))) () + (3,4) """ return self._fs._repr_() def _latex_(self) : r""" EXAMPLES:: sage: G = KleinFourGroup() sage: A = GroupAlgebra(G, ZZ) sage: latex(A(1) + A(A.group().gen(0))) () + (3,4) """ return latex(self._fs)