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

File trac-6670-group_algebra-3.patch, 21.3 KB (added by Martin Raum, 13 years ago)

This is a rebase to 4.3alpha0 .

• ## sage/algebras/group_algebra.py

diff -r 44f70d431d43 sage/algebras/group_algebra.py
 a from sage.rings.all import IntegerRing from sage.groups.group import Group from sage.structure.formal_sum import FormalSums_generic, 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 class GroupAlgebra(Algebra): _cache = dict() def __init__(self, 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. 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: 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 EXAMPLES : sage: F = GroupAlgebraFunctor(KleinFourGroup()) sage: loads(dumps(F)) == F True """ if not base_ring.is_commutative(): raise NotImplementedError, "Base ring must be commutative" self.__group = group ConstructionFunctor.__init__(self, Rings(), Rings()) def group(self) : r""" Return the group which is associtated to this functor. EXAMPLES : 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: 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 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""" EXAMPLES : sage: A = GroupAlgebra(GL(3, GF(7))) sage: A.has_coerce_map_from(GL(3, GF(7))) True """ Algebra.__init__(self, 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 """ 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. # I don't know if that means "is canonically isomorphic to a prime field" # or "is identical to a prime field". def _coerce_impl(self, x): return self(self.base_ring().coerce(x)) ########################################################################### ## GroupAlgebra_class :: elements ########################################################################### def _an_element_impl(self): 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 an element of self. 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] """ try: return self(self._formal_sum_module([ (self.base_ring().random_element(), self.group().random_element()), (self.base_ring().random_element(), self.group().random_element()), ])) except: # base ring or group might not implement .random_element() return self(self._formal_sum_module([ (self.base_ring().an_element(), self.group().an_element()) ])) 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 __call__(self, x, check=True): 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. -- x: either a FormalSum element consisting of elements of self.group(), an element of self.base_ring(), or an element of self.group(). -- check (boolean): whether or not to check that the given elements really do lie in self.group(). Chiefly provided to speed up arithmetic operations with elements that have already been checked to lie in the 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 = AbelianGroup(1) sage: f = G.gen() sage: G = KleinFourGroup() sage: f = G.gen(0) sage: ZG = GroupAlgebra(G) sage: ZG(f) 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)])) 2*f^2 + f f + 2*f^2 sage: G = GL(2,7) sage: OG = GroupAlgebra(G, ZZ[sqrt(5)]) sage: OG(2) sage: OG(FormalSum([ (1, G(2)), (2, RR(0.77)) ]) ) Traceback (most recent call last): ... TypeError: 0.770000000000000 is not an element of group General Linear Group of degree 2 over Finite Field of size 7 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(FormalSum([ (1, G(2)), (2, RR(0.77)) ]), check=False) # random [2 0] [0 2] + 2*0.770000000000000 sage: OG(OG.base_ring().gens()[1]) sqrt5*[1 0] [0 1] """ return GroupAlgebraElement(self, x, check) """ 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] ) ) def __eq__(self, other): r""" Test for equality. 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 False sage: GroupAlgebra(AbelianGroup(2)) == GroupAlgebra(AbelianGroup(1)) False """ if not isinstance(other, GroupAlgebra): return False else: return self.base_ring() == other.base_ring() and self.group() == other.group() 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.""" return "Group algebra of group \"%s\" over base ring %s" % (self.group(), self.base_ring()) 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""" EXAMPLES: sage: GroupAlgebra(SU(2, GF(4,'a'))).element_class() """ return GroupAlgebraElement return GroupAlgebraElement_class def category(self): r""" from sage.categories.all import GroupAlgebras return GroupAlgebras(self.base_ring()) 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" class GroupAlgebraElement(AlgebraElement): if not isinstance(x, Element) : x = IntegerRing()(x) def __init__(self, parent, x, check): 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.__call__ for examples and doctests.""" doctests. EXAMPLES : sage: A = GroupAlgebra(KleinFourGroup(), ZZ) sage: GroupAlgebraElement(A, A._formal_sum_module([(1, KleinFourGroup().gen(0))])) (3,4) """ AlgebraElement.__init__(self, parent) if not hasattr(x, 'parent'): x = IntegerRing()(x) # occasionally coercion framework tries to pass a Python int self._fs = x if isinstance(x, FormalSum): if check: for c,d in x._data: if d.parent() != self.parent().group(): raise TypeError, "%s is not an element of group %s" % (d, self.parent().group()) self._fs = x else: self._fs = x ########################################################################### ## GroupAlgebraElement_class :: Arithmetic ########################################################################### elif self.base_ring().has_coerce_map_from(x.parent()): self._fs = self.parent()._formal_sum_module([ (x, self.parent().group()(1)) ]) elif self.parent().group().has_coerce_map_from(x.parent()): self._fs = self.parent()._formal_sum_module([ (1, self.parent().group()(x)) ]) else: raise TypeError, "Don't know how to create an element of %s from %s" % (self.parent(), x) def _repr_(self): return self._fs._repr_() def _add_(self, other): def _add_(left, right): r""" Add self to other. Add left to right. EXAMPLE: sage: G = GL(3, GF(7)) sage: ZG = GroupAlgebra(G) sage: g1 = G([0,0,2,2,5,0,6,6,2]) 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] """ fs_sum = self._fs + other._fs return self.parent()(fs_sum, check=False) """ return left.parent()(left._fs + right._fs) def _mul_(self, right): r""" Calculate self*right, where both self and right are GroupAlgebraElements. 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: a, b = ZG.group().random_element(), ZG.group().random_element() sage: za, zb = ZG(a), ZG(b) sage: za*ZG(2) # random 2*[4,5,0] sage: za*za == za^2 True """ d1 = self._fs._data d2 = right._fs._data new = [] for (a1, g1) in d1: for a2,g2 in d2: if self.parent().group().is_multiplicative(): new.append( (a1*a2, g1*g2) ) else: new.append( (a1*a2, g1 + g2) ) return self.parent()( self.parent()._formal_sum_module(new), check=False) 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 ] def __eq__(self, other): r""" Test if self is equal to other. 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: a = GroupAlgebra(G)(1) sage: b = GroupAlgebra(G)(2) sage: ZG = GroupAlgebra(G) sage: a = ZG(1) sage: b = ZG(2) sage: a + a == b True sage: a == b sage: a == GroupAlgebra(AbelianGroup(1, [5]))(1) False """ if isinstance(other, GroupAlgebraElement) and self.parent() == other.parent(): return self._fs == other._fs else: return 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)