Dual groups of Finite Multiplicative Abelian Groups#
The basic idea is very simple. Let G be an abelian group and \(G^*\) its dual (i.e., the group of homomorphisms from G to \(\CC^\times\)). Let \(g_j\), \(j=1,..,n\), denote generators of \(G\) - say \(g_j\) is of order \(m_j>1\). There are generators \(X_j\), \(j=1,..,n\), of \(G^*\) for which \(X_j(g_j)=\exp(2\pi i/m_j)\) and \(X_i(g_j)=1\) if \(i\not= j\). These are used to construct \(G^*\).
Sage supports multiplicative abelian groups on any prescribed finite
number \(n > 0\) of generators. Use
AbelianGroup()
function
to create an abelian group, the
dual_group()
method to create its dual, and then the gen()
and gens()
methods to obtain the corresponding generators. You can print the
generators as arbitrary strings using the optional names
argument
to the
dual_group()
method.
EXAMPLES:
sage: F = AbelianGroup(5, [2,5,7,8,9], names='abcde')
sage: (a, b, c, d, e) = F.gens()
sage: Fd = F.dual_group(names='ABCDE')
sage: Fd.base_ring()
Cyclotomic Field of order 2520 and degree 576
sage: A,B,C,D,E = Fd.gens()
sage: A(a)
-1
sage: A(b), A(c), A(d), A(e)
(1, 1, 1, 1)
sage: # needs sage.rings.real_mpfr
sage: Fd = F.dual_group(names='ABCDE', base_ring=CC)
sage: Fd.category()
Category of commutative groups
sage: A,B,C,D,E = Fd.gens()
sage: A(a) # abs tol 1e-8
-1.00000000000000 + 0.00000000000000*I
sage: A(b); A(c); A(d); A(e)
1.00000000000000
1.00000000000000
1.00000000000000
1.00000000000000
>>> from sage.all import *
>>> F = AbelianGroup(Integer(5), [Integer(2),Integer(5),Integer(7),Integer(8),Integer(9)], names='abcde')
>>> (a, b, c, d, e) = F.gens()
>>> Fd = F.dual_group(names='ABCDE')
>>> Fd.base_ring()
Cyclotomic Field of order 2520 and degree 576
>>> A,B,C,D,E = Fd.gens()
>>> A(a)
-1
>>> A(b), A(c), A(d), A(e)
(1, 1, 1, 1)
>>> # needs sage.rings.real_mpfr
>>> Fd = F.dual_group(names='ABCDE', base_ring=CC)
>>> Fd.category()
Category of commutative groups
>>> A,B,C,D,E = Fd.gens()
>>> A(a) # abs tol 1e-8
-1.00000000000000 + 0.00000000000000*I
>>> A(b); A(c); A(d); A(e)
1.00000000000000
1.00000000000000
1.00000000000000
1.00000000000000
AUTHORS:
David Joyner (2006-08) (based on abelian_groups)
David Joyner (2006-10) modifications suggested by William Stein
Volker Braun (2012-11) port to new Parent base. Use tuples for immutables. Default to cyclotomic base ring.
- class sage.groups.abelian_gps.dual_abelian_group.DualAbelianGroup_class(G, names, base_ring)[source]#
Bases:
UniqueRepresentation
,AbelianGroup
Dual of abelian group.
EXAMPLES:
sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde") sage: F.dual_group() Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Cyclotomic Field of order 2520 and degree 576 sage: F = AbelianGroup(4,[15,7,8,9], names="abcd") sage: F.dual_group(base_ring=CC) # needs sage.rings.real_mpfr Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision
>>> from sage.all import * >>> F = AbelianGroup(Integer(5),[Integer(3),Integer(5),Integer(7),Integer(8),Integer(9)], names="abcde") >>> F.dual_group() Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z over Cyclotomic Field of order 2520 and degree 576 >>> F = AbelianGroup(Integer(4),[Integer(15),Integer(7),Integer(8),Integer(9)], names="abcd") >>> F.dual_group(base_ring=CC) # needs sage.rings.real_mpfr Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision
- Element[source]#
alias of
DualAbelianGroupElement
- base_ring()[source]#
Return the scalars over which the group is dualized.
EXAMPLES:
sage: F = AbelianGroup(3,[5,64,729], names=list("abc")) sage: Fd = F.dual_group(base_ring=CC) sage: Fd.base_ring() Complex Field with 53 bits of precision
>>> from sage.all import * >>> F = AbelianGroup(Integer(3),[Integer(5),Integer(64),Integer(729)], names=list("abc")) >>> Fd = F.dual_group(base_ring=CC) >>> Fd.base_ring() Complex Field with 53 bits of precision
- gen(i=0)[source]#
The \(i\)-th generator of the abelian group.
EXAMPLES:
sage: F = AbelianGroup(3, [1,2,3], names='a') sage: Fd = F.dual_group(names="A") sage: Fd.0 1 sage: Fd.1 A1 sage: Fd.gens_orders() (1, 2, 3)
>>> from sage.all import * >>> F = AbelianGroup(Integer(3), [Integer(1),Integer(2),Integer(3)], names='a') >>> Fd = F.dual_group(names="A") >>> Fd.gen(0) 1 >>> Fd.gen(1) A1 >>> Fd.gens_orders() (1, 2, 3)
- gens()[source]#
Return the generators for the group.
OUTPUT: tuple of group elements generating the group
EXAMPLES:
sage: F = AbelianGroup([7,11]).dual_group() sage: F.gens() (X0, X1)
>>> from sage.all import * >>> F = AbelianGroup([Integer(7),Integer(11)]).dual_group() >>> F.gens() (X0, X1)
- gens_orders()[source]#
The orders of the generators of the dual group.
OUTPUT: tuple of integers
EXAMPLES:
sage: F = AbelianGroup([5]*1000) sage: Fd = F.dual_group() sage: invs = Fd.gens_orders(); len(invs) 1000
>>> from sage.all import * >>> F = AbelianGroup([Integer(5)]*Integer(1000)) >>> Fd = F.dual_group() >>> invs = Fd.gens_orders(); len(invs) 1000
- group()[source]#
Return the group that
self
is the dual of.EXAMPLES:
sage: F = AbelianGroup(3,[5,64,729], names=list("abc")) sage: Fd = F.dual_group(base_ring=CC) sage: Fd.group() is F True
>>> from sage.all import * >>> F = AbelianGroup(Integer(3),[Integer(5),Integer(64),Integer(729)], names=list("abc")) >>> Fd = F.dual_group(base_ring=CC) >>> Fd.group() is F True
- invariants()[source]#
The invariants of the dual group.
You should use
gens_orders()
instead.EXAMPLES:
sage: F = AbelianGroup([5]*1000) sage: Fd = F.dual_group() sage: invs = Fd.gens_orders(); len(invs) 1000
>>> from sage.all import * >>> F = AbelianGroup([Integer(5)]*Integer(1000)) >>> Fd = F.dual_group() >>> invs = Fd.gens_orders(); len(invs) 1000
- is_commutative()[source]#
Return
True
since this group is commutative.EXAMPLES:
sage: G = AbelianGroup([2,3,9]) sage: Gd = G.dual_group() sage: Gd.is_commutative() True sage: Gd.is_abelian() True
>>> from sage.all import * >>> G = AbelianGroup([Integer(2),Integer(3),Integer(9)]) >>> Gd = G.dual_group() >>> Gd.is_commutative() True >>> Gd.is_abelian() True
- list()[source]#
Return a tuple of all elements of this group.
EXAMPLES:
sage: G = AbelianGroup([2,3], names="ab") sage: Gd = G.dual_group(names="AB") sage: Gd.list() (1, B, B^2, A, A*B, A*B^2)
>>> from sage.all import * >>> G = AbelianGroup([Integer(2),Integer(3)], names="ab") >>> Gd = G.dual_group(names="AB") >>> Gd.list() (1, B, B^2, A, A*B, A*B^2)
- ngens()[source]#
The number of generators of the dual group.
EXAMPLES:
sage: F = AbelianGroup([7]*100) sage: Fd = F.dual_group() sage: Fd.ngens() 100
>>> from sage.all import * >>> F = AbelianGroup([Integer(7)]*Integer(100)) >>> Fd = F.dual_group() >>> Fd.ngens() 100
- order()[source]#
Return the order of this group.
EXAMPLES:
sage: G = AbelianGroup([2,3,9]) sage: Gd = G.dual_group() sage: Gd.order() 54
>>> from sage.all import * >>> G = AbelianGroup([Integer(2),Integer(3),Integer(9)]) >>> Gd = G.dual_group() >>> Gd.order() 54
- random_element()[source]#
Return a random element of this dual group.
EXAMPLES:
sage: G = AbelianGroup([2,3,9]) sage: Gd = G.dual_group(base_ring=CC) # needs sage.rings.real_mpfr sage: Gd.random_element().parent() is Gd # needs sage.rings.real_mpfr True sage: # needs sage.rings.real_mpfr sage: N = 43^2 - 1 sage: G = AbelianGroup([N], names="a") sage: Gd = G.dual_group(names="A", base_ring=CC) sage: a, = G.gens() sage: A, = Gd.gens() sage: x = a^(N/4); y = a^(N/3); z = a^(N/14) sage: found = [False]*4 sage: while not all(found): ....: X = A*Gd.random_element() ....: found[len([b for b in [x,y,z] if abs(X(b)-1)>10^(-8)])] = True
>>> from sage.all import * >>> G = AbelianGroup([Integer(2),Integer(3),Integer(9)]) >>> Gd = G.dual_group(base_ring=CC) # needs sage.rings.real_mpfr >>> Gd.random_element().parent() is Gd # needs sage.rings.real_mpfr True >>> # needs sage.rings.real_mpfr >>> N = Integer(43)**Integer(2) - Integer(1) >>> G = AbelianGroup([N], names="a") >>> Gd = G.dual_group(names="A", base_ring=CC) >>> a, = G.gens() >>> A, = Gd.gens() >>> x = a**(N/Integer(4)); y = a**(N/Integer(3)); z = a**(N/Integer(14)) >>> found = [False]*Integer(4) >>> while not all(found): ... X = A*Gd.random_element() ... found[len([b for b in [x,y,z] if abs(X(b)-Integer(1))>Integer(10)**(-Integer(8))])] = True
- sage.groups.abelian_gps.dual_abelian_group.is_DualAbelianGroup(x)[source]#
Return
True
if \(x\) is the dual group of an abelian group.EXAMPLES:
sage: from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup sage: F = AbelianGroup(5,[3,5,7,8,9], names=list("abcde")) sage: Fd = F.dual_group() sage: is_DualAbelianGroup(Fd) doctest:warning... DeprecationWarning: the function is_DualAbelianGroup is deprecated; use 'isinstance(..., DualAbelianGroup_class)' instead See https://github.com/sagemath/sage/issues/37898 for details. True sage: F = AbelianGroup(3,[1,2,3], names='a') sage: Fd = F.dual_group() sage: Fd.gens() (1, X1, X2) sage: F.gens() (1, a1, a2)
>>> from sage.all import * >>> from sage.groups.abelian_gps.dual_abelian_group import is_DualAbelianGroup >>> F = AbelianGroup(Integer(5),[Integer(3),Integer(5),Integer(7),Integer(8),Integer(9)], names=list("abcde")) >>> Fd = F.dual_group() >>> is_DualAbelianGroup(Fd) doctest:warning... DeprecationWarning: the function is_DualAbelianGroup is deprecated; use 'isinstance(..., DualAbelianGroup_class)' instead See https://github.com/sagemath/sage/issues/37898 for details. True >>> F = AbelianGroup(Integer(3),[Integer(1),Integer(2),Integer(3)], names='a') >>> Fd = F.dual_group() >>> Fd.gens() (1, X1, X2) >>> F.gens() (1, a1, a2)