Path: blob/master/sage/groups/abelian_gps/dual_abelian_group.py
4107 views
r"""1Basic functionality for dual groups of finite multiplicative Abelian groups23AUTHORS:45- David Joyner (2006-08) (based on abelian_groups)67- David Joyner (2006-10) modifications suggested by William Stein89TODO:1011- additive abelian groups should also be supported.1213The basic idea is very simple. Let G be an abelian group and14`G^*` its dual (i.e., the group of homomorphisms from G to15`\CC^\times`). Let `g_j`,16`j=1,..,n`, denote generators of `G` - say17`g_j` is of order `m_j>1`. There are generators18`X_j`, `j=1,..,n`, of `G^*` for which19`X_j(g_j)=\exp(2\pi i/m_j)` and `X_i(g_j)=1`20if `i\not= j`. These are used to construct `G^*` in21the DualAbelianGroup class below.2223Sage supports multiplicative abelian groups on any prescribed24finite number `n > 0` of generators. Use the25``AbelianGroup`` function to create an abelian group,26the ``DualAbelianGroup`` function to create its dual,27and then the ``gen`` and ``gens`` functions28to obtain the corresponding generators. You can print the29generators as arbitrary strings using the optional30``names`` argument to the31``DualAbelianGroup`` function.32"""3334##########################################################################35# Copyright (C) 2006 David Joyner <[email protected]> and William Stein36#37# Distributed under the terms of the GNU General Public License (GPL):38#39# http://www.gnu.org/licenses/40##########################################################################41424344from sage.rings.infinity import infinity45from sage.rings.arith import LCM46import sage.groups.group as group47from dual_abelian_group_element import DualAbelianGroupElement,is_DualAbelianGroupElement48from sage.misc.mrange import mrange49from sage.rings.integer_ring import IntegerRing50ZZ = IntegerRing()51from sage.rings.complex_field import ComplexField52CC = ComplexField()53from sage.rings.number_field.number_field import CyclotomicField5455def DualAbelianGroup(G, names="X", base_ring=CC):56r"""57Create the dual group of the multiplicative abelian group58`G`.5960INPUT:616263- ``G`` - a finite abelian group6465- ``names`` - (optional) names of generators666768OUTPUT: The dual group of G.6970EXAMPLES::7172sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')73sage: (a, b, c, d, e) = F.gens()74sage: Fd = DualAbelianGroup(F,names='ABCDE')75sage: A,B,C,D,E = Fd.gens()76sage: A(a) ## random77-1.0000000000000000 + 0.00000000000000013834419720915037*I78sage: A(b); A(c); A(d); A(e)791.00000000000000801.00000000000000811.00000000000000821.0000000000000083"""84if G.order() is infinity:85NotImplementedError, "The group must be finite"86#infac = G.invariants()87#n = G.ngens()88#namesG = [G.gen(i) for i in range(n)]89M = DualAbelianGroup_class(G, names, base_ring)90return M9192def is_DualAbelianGroup(x):93"""94Return True if `x` is the dual group of an abelian group.9596EXAMPLES::9798sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup99sage: F = AbelianGroup(5,[3,5,7,8,9],names = list("abcde"))100sage: Fd = DualAbelianGroup(F)101sage: is_DualAbelianGroup(Fd)102True103sage: F = AbelianGroup(3,[1,2,3],names='a')104sage: Fd = DualAbelianGroup(F)105sage: Fd.gens()106(X0, X1)107sage: F.gens()108(a0, a1)109"""110return isinstance(x, DualAbelianGroup_class)111112113class DualAbelianGroup_class(group.AbelianGroup):114"""115Dual of abelian group.116117EXAMPLES::118119sage: F = AbelianGroup(5,[3,5,7,8,9],names = list("abcde"))120sage: DualAbelianGroup(F)121Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision122sage: F = AbelianGroup(4,[15,7,8,9],names = list("abcd"))123sage: DualAbelianGroup(F)124Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision125"""126def __init__(self, G, names="X", bse_ring=None):127"""128If G has invariants invs = [n1,...,nk] then the default base_ring129is CyclotoomicField(N), where N = LCM(n1,...,nk).130"""131if bse_ring == None:132base_ring = CyclotomicField(LCM(G.invariants()))133else:134base_ring = bse_ring135self.__group = G136self._assign_names(names)137self._base_ring = base_ring138139def group(self):140return self.__group141142def base_ring(self):143return self._base_ring144145def __str__(self):146"""147Print method.148149EXAMPLES::150151sage: F = AbelianGroup(3,[5,64,729],names = list("abc"))152sage: Fd = DualAbelianGroup(F)153sage: print Fd154DualAbelianGroup( AbelianGroup ( 3, [5, 64, 729] ) )155"""156s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.invariants())157return s158159def _repr_(self):160"""161EXAMPLES::162163sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')164sage: Fd = DualAbelianGroup(F,names='ABCDE',base_ring = CyclotomicField(2*5*7*8*9))165sage: Fd166Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Cyclotomic Field of order 5040 and degree 1152167sage: Fd = DualAbelianGroup(F,names='ABCDE')168sage: Fd169Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision170"""171G = self.group()172eldv = G.invariants()173gp = ""174for x in eldv:175if x!=0:176gp = gp + "Z/%sZ x "%x177if x==0:178gp = gp + "Z x "179gp = gp[:-2]180s = "Dual of Abelian Group isomorphic to "+gp+" over %s"%self.base_ring()181return s182183def _latex_(self):184r"""185Return latex representation of this group.186187EXAMPLES::188189sage: F = AbelianGroup(3, [2]*3)190sage: Fd = DualAbelianGroup(F)191sage: Fd._latex_()192'$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, [2, 2, 2] ) )$'193"""194s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.invariants())195return s196197def __call__(self, x):198"""199Create an element of this abelian group from `x`.200201EXAMPLES::202203sage: F = AbelianGroup(10, [2]*10)204sage: Fd = DualAbelianGroup(F)205sage: Fd(Fd.2)206X2207sage: Fd(1)2081209"""210if isinstance(x, DualAbelianGroupElement) and x.parent() is self:211return x212return DualAbelianGroupElement(self, x)213214def random_element(self):215"""216Return a random element of this dual group.217218EXAMPLES::219220sage: G = AbelianGroup([2,3,9])221sage: Gd = DualAbelianGroup(G)222sage: Gd.random_element()223X0*X1^2*X2224sage: N = 43^2-1225sage: G = AbelianGroup([N],names="a")226sage: Gd = DualAbelianGroup(G,names="A")227sage: a, = G.gens()228sage: A, = Gd.gens()229sage: x = a^(N/4); y = a^(N/3); z = a^(N/14)230sage: X = Gd.random_element(); X231A^615232sage: len([a for a in [x,y,z] if abs(X(a)-1)>10^(-8)])2332234"""235from sage.misc.prandom import randint236gens = self.gens()237g = gens[0]**0238for i in range(len(gens)):239g = g*gens[i]**(randint(1,gens[i].order()))240return g241242def random(self):243"""244Deprecated. Use self.random_element() instead.245"""246raise NotImplementedError, "Deprecated: use random_element() instead"247248249def gen(self, i=0):250"""251The `i`-th generator of the abelian group.252253EXAMPLES::254255sage: F = AbelianGroup(3,[1,2,3],names='a')256sage: Fd = DualAbelianGroup(F, names="A")257sage: Fd.0258A0259sage: Fd.1260A1261sage: Fd.invariants()262[2, 3]263"""264n = self.group().ngens()265if i < 0 or i >= n:266raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)267x = [0]*int(n)268x[int(i)] = 1269return DualAbelianGroupElement(self, x)270271#def gens(self):272# """273# Return the generators for this subgroup.274#275# """276# n = self.group().ngens()277# return tuple(self.gen(i) for i in range(n))278279def ngens(self):280"""281The number of generators of the dual group.282283EXAMPLES::284285sage: F = AbelianGroup(1000)286sage: Fd = DualAbelianGroup(F)287sage: Fd.ngens()2881000289290This can be slow for 10000 or more generators.291"""292return self.group().ngens()293294def invariants(self):295"""296The invariants of the dual group.297298EXAMPLES::299300sage: F = AbelianGroup(1000)301sage: Fd = DualAbelianGroup(F)302sage: invs = Fd.invariants(); len(invs)3031000304305This can be slow for 10000 or more generators.306"""307return self.group().invariants()308309def __contains__(self,X):310"""311Implements "in".312313EXAMPLES::314315sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")316sage: a,b,c,d,e = F.gens()317sage: Fd = DualAbelianGroup(F, names = "ABCDE")318sage: A,B,C,D,E = Fd.gens()319sage: A*B^2*D^7 in Fd320True321"""322return X.parent() == self and is_DualAbelianGroupElement(X)323324def order(self):325"""326Return the order of this group.327328EXAMPLES::329330sage: G = AbelianGroup([2,3,9])331sage: Gd = DualAbelianGroup(G)332sage: Gd.order()33354334"""335G = self.group()336return G.order()337338def is_commutative(self):339"""340Return True since this group is commutative.341342EXAMPLES::343344sage: G = AbelianGroup([2,3,9])345sage: Gd = DualAbelianGroup(G)346sage: Gd.is_commutative()347True348sage: Gd.is_abelian()349True350"""351return True352353def list(self):354"""355Return list of all elements of this group.356357EXAMPLES::358359sage: G = AbelianGroup([2,3], names = "ab")360sage: Gd = DualAbelianGroup(G, names = "AB")361sage: Gd.list()362[1, B, B^2, A, A*B, A*B^2]363"""364try:365return list(self.__list)366except AttributeError:367pass368if not(self.is_finite()):369raise NotImplementedError, "Group must be finite"370invs = self.invariants()371T = mrange(invs)372n = self.order()373L = [DualAbelianGroupElement(self, t) for t in T]374self.__list = L375return list(self.__list)376377def __iter__(self):378"""379Return an iterator over the elements of this group.380381EXAMPLES::382383sage: G = AbelianGroup([2,3], names = "ab")384sage: Gd = DualAbelianGroup(G, names = "AB")385sage: [X for X in Gd]386[1, B, B^2, A, A*B, A*B^2]387sage: N = 43^2-1388sage: G = AbelianGroup([N],names="a")389sage: Gd = DualAbelianGroup(G,names="A")390sage: a, = G.gens()391sage: A, = Gd.gens()392sage: x = a^(N/4)393sage: y = a^(N/3)394sage: z = a^(N/14)395sage: len([X for X in Gd if abs(X(x)-1)>0.01 and abs(X(y)-1)>0.01 and abs(X(z)-1)>0.01])396880397"""398for g in self.list():399yield g400401402403404405