Path: blob/master/src/sage/groups/abelian_gps/dual_abelian_group_element.py
8815 views
"""1Elements (characters) of the dual group of a finite Abelian group.23To obtain the dual group of a finite Abelian group, use the4:meth:`~sage.groups.abelian_gps.abelian_group.dual_group` method::56sage: F = AbelianGroup([2,3,5,7,8], names="abcde")7sage: F8Multiplicative Abelian group isomorphic to C2 x C3 x C5 x C7 x C8910sage: Fd = F.dual_group(names="ABCDE")11sage: Fd12Dual of Abelian Group isomorphic to Z/2Z x Z/3Z x Z/5Z x Z/7Z x Z/8Z13over Cyclotomic Field of order 840 and degree 1921415The elements of the dual group can be evaluated on elements of the orignial group::1617sage: a,b,c,d,e = F.gens()18sage: A,B,C,D,E = Fd.gens()19sage: A*B^2*D^720A*B^221sage: A(a)22-123sage: B(b)24zeta840^140 - 125sage: CC(_) # abs tol 1e-826-0.499999999999995 + 0.866025403784447*I27sage: A(a*b)28-129sage: (A*B*C^2*D^20*E^65).exponents()30(1, 1, 2, 6, 1)31sage: B^(-1)32B^23334AUTHORS:3536- David Joyner (2006-07); based on abelian_group_element.py.3738- David Joyner (2006-10); modifications suggested by William Stein.3940- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.41Default to cyclotomic base ring.42"""4344###########################################################################45# Copyright (C) 2006 William Stein <[email protected]>46# Copyright (C) 2006 David Joyner <[email protected]>47# Copyright (C) 2012 Volker Braun <[email protected]>48#49# Distributed under the terms of the GNU General Public License (GPL)50# http://www.gnu.org/licenses/51###########################################################################5253import operator5455from sage.rings.integer import Integer56from sage.rings.infinity import infinity57from sage.rings.arith import *58from sage.misc.misc import prod59from sage.misc.functional import exp60from sage.rings.complex_field import is_ComplexField61from sage.groups.abelian_gps.element_base import AbelianGroupElementBase6263def add_strings(x, z=0):64"""65This was in sage.misc.misc but commented out. Needed to add66lists of strings in the word_problem method below.6768Return the sum of the elements of x. If x is empty,69return z.7071INPUT:7273- ``x`` -- iterable7475- ``z`` -- the ``0`` that will be returned if ``x`` is empty.7677OUTPUT:7879The sum of the elements of ``x``.8081EXAMPLES::8283sage: from sage.groups.abelian_gps.dual_abelian_group_element import add_strings84sage: add_strings([], z='empty')85'empty'86sage: add_strings(['a', 'b', 'c'])87'abc'88"""89if len(x) == 0:90return z91if not isinstance(x, list):92m = x.__iter__()93y = m.next()94return reduce(operator.add, m, y)95else:96return reduce(operator.add, x[1:], x[0])979899def is_DualAbelianGroupElement(x):100"""101Test whether ``x`` is a dual Abelian group element.102103INPUT:104105- ``x`` -- anything.106107OUTPUT:108109Boolean.110111EXAMPLES::112113sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroupElement114sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")).dual_group()115sage: is_DualAbelianGroupElement(F)116False117sage: is_DualAbelianGroupElement(F.an_element())118True119"""120return isinstance(x, DualAbelianGroupElement)121122123class DualAbelianGroupElement(AbelianGroupElementBase):124"""125Base class for abelian group elements126"""127128def __call__(self, g):129"""130Evaluate ``self`` on a group element ``g``.131132OUTPUT:133134An element in135:meth:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class.base_ring`.136137EXAMPLES::138139sage: F = AbelianGroup(5, [2,3,5,7,8], names="abcde")140sage: a,b,c,d,e = F.gens()141sage: Fd = F.dual_group(names="ABCDE")142sage: A,B,C,D,E = Fd.gens()143sage: A*B^2*D^7144A*B^2145sage: A(a)146-1147sage: B(b)148zeta840^140 - 1149sage: CC(B(b)) # abs tol 1e-8150-0.499999999999995 + 0.866025403784447*I151sage: A(a*b)152-1153"""154F = self.parent().base_ring()155expsX = self.exponents()156expsg = g.exponents()157order = self.parent().gens_orders()158N = LCM(order)159if is_ComplexField(F):160from sage.symbolic.constants import pi161I = F.gen()162PI = F(pi)163ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/order[i]) for i in range(len(expsX))])164return ans165ans = F(1) ## assumes F is the cyclotomic field166zeta = F.gen()167for i in range(len(expsX)):168order_noti = N/order[i]169ans = ans*zeta**(expsX[i]*expsg[i]*order_noti)170return ans171172def word_problem(self, words, display=True):173"""174This is a rather hackish method and is included for completeness.175176The word problem for an instance of DualAbelianGroup as it can177for an AbelianGroup. The reason why is that word problem178for an instance of AbelianGroup simply calls GAP (which179has abelian groups implemented) and invokes "EpimorphismFromFreeGroup"180and "PreImagesRepresentative". GAP does not have duals of181abelian groups implemented. So, by using the same name182for the generators, the method below converts the problem for183the dual group to the corresponding problem on the group184itself and uses GAP to solve that.185186EXAMPLES::187188sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde")189sage: Gd = G.dual_group(names="abcde")190sage: a,b,c,d,e = Gd.gens()191sage: u = a^3*b*c*d^2*e^5192sage: v = a^2*b*c^2*d^3*e^3193sage: w = a^7*b^3*c^5*d^4*e^4194sage: x = a^3*b^2*c^2*d^3*e^5195sage: y = a^2*b^4*c^2*d^4*e^5196sage: e.word_problem([u,v,w,x,y],display=False)197[[b^2*c^2*d^3*e^5, 245]]198199The command e.word_problem([u,v,w,x,y],display=True) returns200the same list but also prints $e = (b^2*c^2*d^3*e^5)^245$.201"""202## First convert the problem to one using AbelianGroups203import copy204from sage.groups.abelian_gps.abelian_group import AbelianGroup205from sage.interfaces.all import gap206M = self.parent()207G = M.group()208gens = M.variable_names()209g = prod([G.gen(i)**(self.list()[i]) for i in range(G.ngens())])210gap.eval("l:=One(Rationals)") ## trick needed for LL line below to keep Sage from parsing211s1 = "gens := GeneratorsOfGroup(%s)"%G._gap_init_()212gap.eval(s1)213for i in range(len(gens)):214cmd = ("%s := gens["+str(i+1)+"]")%gens[i]215gap.eval(cmd)216s2 = "g0:=%s; gensH:=%s"%(str(g),words)217gap.eval(s2)218s3 = 'G:=Group(gens); H:=Group(gensH)'219gap.eval(s3)220phi = gap.eval("hom:=EpimorphismFromFreeGroup(H)")221l1 = gap.eval("ans:=PreImagesRepresentative(hom,g0)")222l2 = copy.copy(l1)223l4 = []224l3 = l1.split("*")225for i in range(1,len(words)+1):226l2 = l2.replace("x"+str(i),"("+str(words[i-1])+")")227l3 = eval(gap.eval("L3:=ExtRepOfObj(ans)"))228nn = eval(gap.eval("n:=Int(Length(L3)/2)"))229LL1 = eval(gap.eval("L4:=List([l..n],i->L3[2*i])")) ## note the l not 1230LL2 = eval(gap.eval("L5:=List([l..n],i->L3[2*i-1])")) ## note the l not 1231if display:232s = str(g)+" = "+add_strings(["("+str(words[LL2[i]-1])+")^"+str(LL1[i])+"*" for i in range(nn)])233m = len(s)234print " ",s[:m-1],"\n"235return [[words[LL2[i]-1],LL1[i]] for i in range(nn)]236237238239240241242