Path: blob/master/src/sage/groups/abelian_gps/element_base.py
8815 views
"""1Base class for abelian group elements23This is the base class for both4:mod:`~sage.groups.abelian_gps.abelian_group_element` and5:mod:`~sage.groups.abelian_gps.dual_abelian_group_element`.67As always, elements are immutable once constructed.8"""91011###########################################################################12# Copyright (C) 2006 William Stein <[email protected]>13# Copyright (C) 2006 David Joyner <[email protected]>14# Copyright (C) 2012 Volker Braun <[email protected]>15#16# Distributed under the terms of the GNU General Public License (GPL)17# http://www.gnu.org/licenses/18###########################################################################1920from sage.structure.element import MultiplicativeGroupElement21from sage.misc.cachefunc import cached_method22from sage.rings.arith import GCD, LCM23from sage.rings.integer import Integer24from sage.rings.integer_ring import ZZ25from sage.rings.infinity import infinity262728class AbelianGroupElementBase(MultiplicativeGroupElement):29"""30Base class for abelian group elements3132The group element is defined by a tuple whose ``i``-th entry is an33integer in the range from 0 (inclusively) to ``G.gen(i).order()``34(exclusively) if the `i`-th generator is of finite order, and an35arbitrary integer if the `i`-th generator is of infinte order.3637INPUT:3839- ``exponents`` -- ``1`` or a list/tuple/iterable of integers. The40exponent vector (with respect to the parent generators) defining41the group element.4243- ``parent`` -- Abelian group. The parent of the group element.4445EXAMPLES::4647sage: F = AbelianGroup(3,[7,8,9])48sage: Fd = F.dual_group(names="ABC")49sage: A,B,C = Fd.gens()50sage: A*B^-1 in Fd51True52"""5354def __init__(self, parent, exponents):55"""56Create an element.5758EXAMPLES::5960sage: F = AbelianGroup(3,[7,8,9])61sage: Fd = F.dual_group(names="ABC")62sage: A,B,C = Fd.gens()63sage: A*B^-1 in Fd64True65"""66MultiplicativeGroupElement.__init__(self, parent)67n = parent.ngens()68if exponents == 1:69self._exponents = tuple( ZZ.zero() for i in range(n) )70else:71self._exponents = tuple( ZZ(e) for e in exponents )72if len(self._exponents) != n:73raise IndexError('argument length (= %s) must be %s.'%(len(exponents), n))7475def exponents(self):76"""77The exponents of the generators defining the group element.7879OUTPUT:8081A tuple of integers for an abelian group element. The integer82can be arbitrary if the corresponding generator has infinite83order. If the generator is of finite order, the integer is in84the range from 0 (inclusive) to the order (exclusive).8586EXAMPLES::8788sage: F.<a,b,c,f> = AbelianGroup([7,8,9,0])89sage: (a^3*b^2*c).exponents()90(3, 2, 1, 0)91sage: F([3, 2, 1, 0])92a^3*b^2*c93sage: (c^42).exponents()94(0, 0, 6, 0)95sage: (f^42).exponents()96(0, 0, 0, 42)97"""98return self._exponents99100def list(self):101"""102Return a copy of the exponent vector.103104Use :meth:`exponents` instead.105106OUTPUT:107108The underlying coordinates used to represent this element. If109this is a word in an abelian group on `n` generators, then110this is a list of nonnegative integers of length `n`.111112EXAMPLES::113114sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")115sage: a,b,c,d,e = F.gens()116sage: Ad = F.dual_group(names="ABCDE")117sage: A,B,C,D,E = Ad.gens()118sage: (A*B*C^2*D^20*E^65).exponents()119(1, 1, 2, 6, 1)120sage: X = A*B*C^2*D^2*E^-6121sage: X.exponents()122(1, 1, 2, 2, 2)123"""124# to be deprecated (really, return a list??). Use exponents() instead.125return list(self._exponents)126127def _repr_(self):128"""129Return a string representation of ``self``.130131OUTPUT:132133String.134135EXAMPLES::136137sage: G = AbelianGroup([2])138sage: G.gen(0)._repr_()139'f'140sage: G.one()._repr_()141'1'142"""143s = ""144G = self.parent()145for v_i, x_i in zip(self.exponents(), G.variable_names()):146if v_i == 0:147continue148if len(s) > 0:149s += '*'150if v_i == 1:151s += str(x_i)152else:153s += str(x_i) + '^' + str(v_i)154if s:155return s156else:157return '1'158159def __cmp__(self, other):160"""161Compare ``self`` and ``other``.162163OUTPUT:164165``-1``, ``0``, or ``+1``166167EXAMPLES::168169sage: G.<a,b> = AbelianGroup([2,3])170sage: cmp(a,b)1711172173sage: Gd.<A,B> = G.dual_group()174sage: cmp(A,B)1751176"""177return cmp(self._exponents, other._exponents)178179@cached_method180def order(self):181"""182Return the order of this element.183184OUTPUT:185186An integer or ``infinity``.187188EXAMPLES::189190sage: F = AbelianGroup(3,[7,8,9])191sage: Fd = F.dual_group()192sage: A,B,C = Fd.gens()193sage: (B*C).order()19472195196sage: F = AbelianGroup(3,[7,8,9]); F197Multiplicative Abelian group isomorphic to C7 x C8 x C9198sage: F.gens()[2].order()1999200sage: a,b,c = F.gens()201sage: (b*c).order()20272203sage: G = AbelianGroup(3,[7,8,9])204sage: type((G.0 * G.1).order())==Integer205True206"""207M = self.parent()208order = M.gens_orders()209L = self.exponents()210N = LCM([order[i]/GCD(order[i],L[i]) for i in range(len(order)) if L[i]!=0])211if N == 0:212return infinity213else:214return ZZ(N)215216multiplicative_order = order217218def _div_(left, right):219"""220Divide ``left`` and ``right``221222TESTS::223224sage: G.<a,b> = AbelianGroup(2)225sage: a/b226a*b^-1227sage: a._div_(b)228a*b^-1229"""230G = left.parent()231assert G is right.parent()232exponents = [ (x-y)%order if order!=0 else x-y233for x, y, order in234zip(left._exponents, right._exponents, G.gens_orders()) ]235return G.element_class(G, exponents)236237def _mul_(left, right):238"""239Multiply ``left`` and ``right``240241TESTS::242243sage: G.<a,b> = AbelianGroup(2)244sage: a*b245a*b246sage: a._mul_(b)247a*b248"""249G = left.parent()250assert G is right.parent()251exponents = [ (x+y)%order if order!=0 else x+y252for x, y, order in253zip(left._exponents, right._exponents, G.gens_orders()) ]254return G.element_class(G, exponents)255256def __pow__(self, n):257"""258Exponentiate ``self``259260TESTS::261262sage: G.<a,b> = AbelianGroup(2)263sage: a^3264a^3265"""266m = Integer(n)267if n != m:268raise TypeError('argument n (= '+str(n)+') must be an integer.')269G = self.parent()270exponents = [ (m*e) % order if order!=0 else m*e271for e,order in zip(self._exponents, G.gens_orders()) ]272return G.element_class(G, exponents)273274def inverse(self):275"""276Returns the inverse element.277278EXAMPLE::279280sage: G.<a,b> = AbelianGroup([0,5])281sage: a.inverse()282a^-1283sage: a.__invert__()284a^-1285sage: a^-1286a^-1287sage: ~a288a^-1289sage: (a*b).exponents()290(1, 1)291sage: (a*b).inverse().exponents()292(-1, 4)293"""294G = self.parent()295exponents = [ (-e)%order if order!=0 else -e296for e,order in zip(self._exponents, G.gens_orders()) ]297return G.element_class(G, exponents)298299__invert__ = inverse300301def is_trivial(self):302"""303Test whether ``self`` is the trivial group element ``1``.304305OUTPUT:306307Boolean.308309EXAMPLES::310311sage: G.<a,b> = AbelianGroup([0,5])312sage: (a^5).is_trivial()313False314sage: (b^5).is_trivial()315True316"""317return all(e==0 for e in self._exponents)318319320