Path: blob/master/src/sage/groups/abelian_gps/dual_abelian_group.py
8815 views
r"""1Dual groups of Finite Multiplicative Abelian Groups23The basic idea is very simple. Let G be an abelian group and `G^*` its4dual (i.e., the group of homomorphisms from G to `\CC^\times`). Let5`g_j`, `j=1,..,n`, denote generators of `G` - say `g_j` is of order6`m_j>1`. There are generators `X_j`, `j=1,..,n`, of `G^*` for which7`X_j(g_j)=\exp(2\pi i/m_j)` and `X_i(g_j)=1` if `i\not= j`. These are8used to construct `G^*`.910Sage supports multiplicative abelian groups on any prescribed finite11number `n > 0` of generators. Use12:func:`~sage.groups.abelian_gps.abelian_group.AbelianGroup` function13to create an abelian group, the14:meth:`~sage.groups.abelian_gps.abelian_group.AbelianGroup_class.dual_group`15method to create its dual, and then the :meth:`gen` and :meth:`gens`16methods to obtain the corresponding generators. You can print the17generators as arbitrary strings using the optional ``names`` argument18to the19:meth:`~sage.groups.abelian_gps.abelian_group.AbelianGroup_class.dual_group`20method.2122EXAMPLES::2324sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')25sage: (a, b, c, d, e) = F.gens()2627sage: Fd = F.dual_group(names='ABCDE')28sage: Fd.base_ring()29Cyclotomic Field of order 2520 and degree 57630sage: A,B,C,D,E = Fd.gens()31sage: A(a)32-133sage: A(b), A(c), A(d), A(e)34(1, 1, 1, 1)3536sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)37sage: A,B,C,D,E = Fd.gens()38sage: A(a) # abs tol 1e-839-1.00000000000000 + 0.00000000000000*I40sage: A(b); A(c); A(d); A(e)411.00000000000000421.00000000000000431.00000000000000441.000000000000004546AUTHORS:4748- David Joyner (2006-08) (based on abelian_groups)4950- David Joyner (2006-10) modifications suggested by William Stein5152- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.53Default to cyclotomic base ring.54"""5556###########################################################################57# Copyright (C) 2006 William Stein <[email protected]>58# Copyright (C) 2006 David Joyner <[email protected]>59# Copyright (C) 2012 Volker Braun <[email protected]>60#61# Distributed under the terms of the GNU General Public License (GPL)62# http://www.gnu.org/licenses/63###########################################################################6465from sage.rings.infinity import infinity66from sage.structure.unique_representation import UniqueRepresentation67from sage.groups.abelian_gps.dual_abelian_group_element import (68DualAbelianGroupElement, is_DualAbelianGroupElement )69from sage.misc.mrange import mrange70from sage.misc.cachefunc import cached_method71from sage.groups.group import AbelianGroup as AbelianGroupBase727374def is_DualAbelianGroup(x):75"""76Return True if `x` is the dual group of an abelian group.7778EXAMPLES::7980sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup81sage: F = AbelianGroup(5,[3,5,7,8,9], names=list("abcde"))82sage: Fd = F.dual_group()83sage: is_DualAbelianGroup(Fd)84True85sage: F = AbelianGroup(3,[1,2,3], names='a')86sage: Fd = F.dual_group()87sage: Fd.gens()88(1, X1, X2)89sage: F.gens()90(1, a1, a2)91"""92return isinstance(x, DualAbelianGroup_class)939495class DualAbelianGroup_class(UniqueRepresentation, AbelianGroupBase):96"""97Dual of abelian group.9899EXAMPLES::100101sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")102sage: F.dual_group()103Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z104over Cyclotomic Field of order 2520 and degree 576105sage: F = AbelianGroup(4,[15,7,8,9], names="abcd")106sage: F.dual_group(base_ring=CC)107Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z108over Complex Field with 53 bits of precision109"""110Element = DualAbelianGroupElement111112def __init__(self, G, names, base_ring):113"""114The Python constructor115116EXAMPLES::117118sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")119sage: F.dual_group()120Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z121over Cyclotomic Field of order 2520 and degree 576122"""123self._base_ring = base_ring124self._group = G125names = self.normalize_names(G.ngens(), names)126self._assign_names(names)127AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()128129def group(self):130"""131Return the group that ``self`` is the dual of.132133EXAMPLES::134135sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))136sage: Fd = F.dual_group(base_ring=CC)137sage: Fd.group() is F138True139"""140return self._group141142def base_ring(self):143"""144Return the scalars over which the group is dualized.145146EXAMPLES::147148sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))149sage: Fd = F.dual_group(base_ring=CC)150sage: Fd.base_ring()151Complex Field with 53 bits of precision152"""153return self._base_ring154155def __str__(self):156"""157Print method.158159EXAMPLES::160161sage: F = AbelianGroup(3,[5,64,729], names=list("abc"))162sage: Fd = F.dual_group(base_ring=CC)163sage: print Fd164DualAbelianGroup( AbelianGroup ( 3, (5, 64, 729) ) )165"""166s = "DualAbelianGroup( AbelianGroup ( %s, %s ) )"%(self.ngens(), self.gens_orders())167return s168169def _repr_(self):170"""171Return a string representation.172173EXAMPLES::174175sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')176sage: Fd = F.dual_group(names='ABCDE', base_ring=CyclotomicField(2*5*7*8*9))177sage: Fd # indirect doctest178Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z179over Cyclotomic Field of order 5040 and degree 1152180sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)181sage: Fd182Dual of Abelian Group isomorphic to Z/2Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z183over Complex Field with 53 bits of precision184"""185G = self.group()186eldv = G.gens_orders()187gp = ""188for x in eldv:189if x!=0:190gp = gp + "Z/%sZ x "%x191if x==0:192gp = gp + "Z x "193gp = gp[:-2].strip()194s = 'Dual of Abelian Group isomorphic to ' + gp + ' over ' + str(self.base_ring())195return s196197def _latex_(self):198r"""199Return latex representation of this group.200201EXAMPLES::202203sage: F = AbelianGroup(3, [2]*3)204sage: Fd = F.dual_group()205sage: Fd._latex_()206'$\\mathrm{DualAbelianGroup}( AbelianGroup ( 3, (2, 2, 2) ) )$'207"""208s = "$\mathrm{DualAbelianGroup}( AbelianGroup ( %s, %s ) )$"%(self.ngens(), self.gens_orders())209return s210211def random_element(self):212"""213Return a random element of this dual group.214215EXAMPLES::216217sage: G = AbelianGroup([2,3,9])218sage: Gd = G.dual_group(base_ring=CC)219sage: Gd.random_element()220X1^2221222sage: N = 43^2-1223sage: G = AbelianGroup([N],names="a")224sage: Gd = G.dual_group(names="A", base_ring=CC)225sage: a, = G.gens()226sage: A, = Gd.gens()227sage: x = a^(N/4); y = a^(N/3); z = a^(N/14)228sage: X = A*Gd.random_element(); X229A^615230sage: len([a for a in [x,y,z] if abs(X(a)-1)>10^(-8)])2312232"""233from sage.misc.prandom import randint234result = self.one()235for g in self.gens():236order = g.order()237result *= g**(randint(0,order))238return result239240def gen(self, i=0):241"""242The `i`-th generator of the abelian group.243244EXAMPLES::245246sage: F = AbelianGroup(3,[1,2,3],names='a')247sage: Fd = F.dual_group(names="A")248sage: Fd.02491250sage: Fd.1251A1252sage: Fd.gens_orders()253(1, 2, 3)254"""255n = self.group().ngens()256if i < 0 or i >= n:257raise IndexError, "Argument i (= %s) must be between 0 and %s."%(i, n-1)258x = [0]*n259if self.gens_orders()[i] != 1:260x[i] = 1261return self.element_class(self, x)262263def gens(self):264"""265Return the generators for the group.266267OUTPUT:268269A tuple of group elements generating the group.270271EXAMPLES::272273sage: F = AbelianGroup([7,11]).dual_group()274sage: F.gens()275(X0, X1)276"""277n = self.group().ngens()278return tuple(self.gen(i) for i in range(n))279280def ngens(self):281"""282The number of generators of the dual group.283284EXAMPLES::285286sage: F = AbelianGroup([7]*100)287sage: Fd = F.dual_group()288sage: Fd.ngens()289100290"""291return self.group().ngens()292293def gens_orders(self):294"""295The orders of the generators of the dual group.296297OUTPUT:298299A tuple of integers.300301EXAMPLES::302303sage: F = AbelianGroup([5]*1000)304sage: Fd = F.dual_group()305sage: invs = Fd.gens_orders(); len(invs)3061000307"""308return self.group().gens_orders()309310def invariants(self):311"""312The invariants of the dual group.313314You should use :meth:`gens_orders` instead.315316EXAMPLES::317318sage: F = AbelianGroup([5]*1000)319sage: Fd = F.dual_group()320sage: invs = Fd.gens_orders(); len(invs)3211000322"""323# TODO: deprecate324return self.group().gens_orders()325326def __contains__(self,X):327"""328Implements "in".329330EXAMPLES::331332sage: F = AbelianGroup(5,[2, 3, 5, 7, 8], names="abcde")333sage: a,b,c,d,e = F.gens()334sage: Fd = F.dual_group(names = "ABCDE")335sage: A,B,C,D,E = Fd.gens()336sage: A*B^2*D^7 in Fd337True338"""339return X.parent() == self and is_DualAbelianGroupElement(X)340341def order(self):342"""343Return the order of this group.344345EXAMPLES::346347sage: G = AbelianGroup([2,3,9])348sage: Gd = G.dual_group()349sage: Gd.order()35054351"""352G = self.group()353return G.order()354355def is_commutative(self):356"""357Return True since this group is commutative.358359EXAMPLES::360361sage: G = AbelianGroup([2,3,9])362sage: Gd = G.dual_group()363sage: Gd.is_commutative()364True365sage: Gd.is_abelian()366True367"""368return True369370@cached_method371def list(self):372"""373Return tuple of all elements of this group.374375EXAMPLES::376377sage: G = AbelianGroup([2,3], names="ab")378sage: Gd = G.dual_group(names="AB")379sage: Gd.list()380(1, B, B^2, A, A*B, A*B^2)381"""382if not(self.is_finite()):383raise NotImplementedError, "Group must be finite"384invs = self.gens_orders()385T = mrange(invs)386n = self.order()387L = tuple( self(t) for t in T )388return L389390def __iter__(self):391"""392Return an iterator over the elements of this group.393394EXAMPLES::395396sage: G = AbelianGroup([2,3], names="ab")397sage: Gd = G.dual_group(names="AB")398sage: [X for X in Gd]399[1, B, B^2, A, A*B, A*B^2]400sage: N = 43^2-1401sage: G = AbelianGroup([N],names="a")402sage: Gd = G.dual_group(names="A", base_ring=CC)403sage: a, = G.gens()404sage: A, = Gd.gens()405sage: x = a^(N/4)406sage: y = a^(N/3)407sage: z = a^(N/14)408sage: 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])409880410"""411for g in self.list():412yield g413414415416417418