Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/abelian_gps/dual_abelian_group_element.py
8815 views
1
"""
2
Elements (characters) of the dual group of a finite Abelian group.
3
4
To obtain the dual group of a finite Abelian group, use the
5
:meth:`~sage.groups.abelian_gps.abelian_group.dual_group` method::
6
7
sage: F = AbelianGroup([2,3,5,7,8], names="abcde")
8
sage: F
9
Multiplicative Abelian group isomorphic to C2 x C3 x C5 x C7 x C8
10
11
sage: Fd = F.dual_group(names="ABCDE")
12
sage: Fd
13
Dual of Abelian Group isomorphic to Z/2Z x Z/3Z x Z/5Z x Z/7Z x Z/8Z
14
over Cyclotomic Field of order 840 and degree 192
15
16
The elements of the dual group can be evaluated on elements of the orignial group::
17
18
sage: a,b,c,d,e = F.gens()
19
sage: A,B,C,D,E = Fd.gens()
20
sage: A*B^2*D^7
21
A*B^2
22
sage: A(a)
23
-1
24
sage: B(b)
25
zeta840^140 - 1
26
sage: CC(_) # abs tol 1e-8
27
-0.499999999999995 + 0.866025403784447*I
28
sage: A(a*b)
29
-1
30
sage: (A*B*C^2*D^20*E^65).exponents()
31
(1, 1, 2, 6, 1)
32
sage: B^(-1)
33
B^2
34
35
AUTHORS:
36
37
- David Joyner (2006-07); based on abelian_group_element.py.
38
39
- David Joyner (2006-10); modifications suggested by William Stein.
40
41
- Volker Braun (2012-11) port to new Parent base. Use tuples for immutables.
42
Default to cyclotomic base ring.
43
"""
44
45
###########################################################################
46
# Copyright (C) 2006 William Stein <[email protected]>
47
# Copyright (C) 2006 David Joyner <[email protected]>
48
# Copyright (C) 2012 Volker Braun <[email protected]>
49
#
50
# Distributed under the terms of the GNU General Public License (GPL)
51
# http://www.gnu.org/licenses/
52
###########################################################################
53
54
import operator
55
56
from sage.rings.integer import Integer
57
from sage.rings.infinity import infinity
58
from sage.rings.arith import *
59
from sage.misc.misc import prod
60
from sage.misc.functional import exp
61
from sage.rings.complex_field import is_ComplexField
62
from sage.groups.abelian_gps.element_base import AbelianGroupElementBase
63
64
def add_strings(x, z=0):
65
"""
66
This was in sage.misc.misc but commented out. Needed to add
67
lists of strings in the word_problem method below.
68
69
Return the sum of the elements of x. If x is empty,
70
return z.
71
72
INPUT:
73
74
- ``x`` -- iterable
75
76
- ``z`` -- the ``0`` that will be returned if ``x`` is empty.
77
78
OUTPUT:
79
80
The sum of the elements of ``x``.
81
82
EXAMPLES::
83
84
sage: from sage.groups.abelian_gps.dual_abelian_group_element import add_strings
85
sage: add_strings([], z='empty')
86
'empty'
87
sage: add_strings(['a', 'b', 'c'])
88
'abc'
89
"""
90
if len(x) == 0:
91
return z
92
if not isinstance(x, list):
93
m = x.__iter__()
94
y = m.next()
95
return reduce(operator.add, m, y)
96
else:
97
return reduce(operator.add, x[1:], x[0])
98
99
100
def is_DualAbelianGroupElement(x):
101
"""
102
Test whether ``x`` is a dual Abelian group element.
103
104
INPUT:
105
106
- ``x`` -- anything.
107
108
OUTPUT:
109
110
Boolean.
111
112
EXAMPLES::
113
114
sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroupElement
115
sage: F = AbelianGroup(5,[5,5,7,8,9],names = list("abcde")).dual_group()
116
sage: is_DualAbelianGroupElement(F)
117
False
118
sage: is_DualAbelianGroupElement(F.an_element())
119
True
120
"""
121
return isinstance(x, DualAbelianGroupElement)
122
123
124
class DualAbelianGroupElement(AbelianGroupElementBase):
125
"""
126
Base class for abelian group elements
127
"""
128
129
def __call__(self, g):
130
"""
131
Evaluate ``self`` on a group element ``g``.
132
133
OUTPUT:
134
135
An element in
136
:meth:`~sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class.base_ring`.
137
138
EXAMPLES::
139
140
sage: F = AbelianGroup(5, [2,3,5,7,8], names="abcde")
141
sage: a,b,c,d,e = F.gens()
142
sage: Fd = F.dual_group(names="ABCDE")
143
sage: A,B,C,D,E = Fd.gens()
144
sage: A*B^2*D^7
145
A*B^2
146
sage: A(a)
147
-1
148
sage: B(b)
149
zeta840^140 - 1
150
sage: CC(B(b)) # abs tol 1e-8
151
-0.499999999999995 + 0.866025403784447*I
152
sage: A(a*b)
153
-1
154
"""
155
F = self.parent().base_ring()
156
expsX = self.exponents()
157
expsg = g.exponents()
158
order = self.parent().gens_orders()
159
N = LCM(order)
160
if is_ComplexField(F):
161
from sage.symbolic.constants import pi
162
I = F.gen()
163
PI = F(pi)
164
ans = prod([exp(2*PI*I*expsX[i]*expsg[i]/order[i]) for i in range(len(expsX))])
165
return ans
166
ans = F(1) ## assumes F is the cyclotomic field
167
zeta = F.gen()
168
for i in range(len(expsX)):
169
order_noti = N/order[i]
170
ans = ans*zeta**(expsX[i]*expsg[i]*order_noti)
171
return ans
172
173
def word_problem(self, words, display=True):
174
"""
175
This is a rather hackish method and is included for completeness.
176
177
The word problem for an instance of DualAbelianGroup as it can
178
for an AbelianGroup. The reason why is that word problem
179
for an instance of AbelianGroup simply calls GAP (which
180
has abelian groups implemented) and invokes "EpimorphismFromFreeGroup"
181
and "PreImagesRepresentative". GAP does not have duals of
182
abelian groups implemented. So, by using the same name
183
for the generators, the method below converts the problem for
184
the dual group to the corresponding problem on the group
185
itself and uses GAP to solve that.
186
187
EXAMPLES::
188
189
sage: G = AbelianGroup(5,[3, 5, 5, 7, 8],names="abcde")
190
sage: Gd = G.dual_group(names="abcde")
191
sage: a,b,c,d,e = Gd.gens()
192
sage: u = a^3*b*c*d^2*e^5
193
sage: v = a^2*b*c^2*d^3*e^3
194
sage: w = a^7*b^3*c^5*d^4*e^4
195
sage: x = a^3*b^2*c^2*d^3*e^5
196
sage: y = a^2*b^4*c^2*d^4*e^5
197
sage: e.word_problem([u,v,w,x,y],display=False)
198
[[b^2*c^2*d^3*e^5, 245]]
199
200
The command e.word_problem([u,v,w,x,y],display=True) returns
201
the same list but also prints $e = (b^2*c^2*d^3*e^5)^245$.
202
"""
203
## First convert the problem to one using AbelianGroups
204
import copy
205
from sage.groups.abelian_gps.abelian_group import AbelianGroup
206
from sage.interfaces.all import gap
207
M = self.parent()
208
G = M.group()
209
gens = M.variable_names()
210
g = prod([G.gen(i)**(self.list()[i]) for i in range(G.ngens())])
211
gap.eval("l:=One(Rationals)") ## trick needed for LL line below to keep Sage from parsing
212
s1 = "gens := GeneratorsOfGroup(%s)"%G._gap_init_()
213
gap.eval(s1)
214
for i in range(len(gens)):
215
cmd = ("%s := gens["+str(i+1)+"]")%gens[i]
216
gap.eval(cmd)
217
s2 = "g0:=%s; gensH:=%s"%(str(g),words)
218
gap.eval(s2)
219
s3 = 'G:=Group(gens); H:=Group(gensH)'
220
gap.eval(s3)
221
phi = gap.eval("hom:=EpimorphismFromFreeGroup(H)")
222
l1 = gap.eval("ans:=PreImagesRepresentative(hom,g0)")
223
l2 = copy.copy(l1)
224
l4 = []
225
l3 = l1.split("*")
226
for i in range(1,len(words)+1):
227
l2 = l2.replace("x"+str(i),"("+str(words[i-1])+")")
228
l3 = eval(gap.eval("L3:=ExtRepOfObj(ans)"))
229
nn = eval(gap.eval("n:=Int(Length(L3)/2)"))
230
LL1 = eval(gap.eval("L4:=List([l..n],i->L3[2*i])")) ## note the l not 1
231
LL2 = eval(gap.eval("L5:=List([l..n],i->L3[2*i-1])")) ## note the l not 1
232
if display:
233
s = str(g)+" = "+add_strings(["("+str(words[LL2[i]-1])+")^"+str(LL1[i])+"*" for i in range(nn)])
234
m = len(s)
235
print " ",s[:m-1],"\n"
236
return [[words[LL2[i]-1],LL1[i]] for i in range(nn)]
237
238
239
240
241
242