Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Finitely generated abelian groups with GAP.
This module provides a python wrapper for abelian groups in GAP.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: AbelianGroupGap([3,5]) Abelian group with gap, generator orders (3, 5)
For infinite abelian groups we use the GAP package ``Polycyclic``::
sage: AbelianGroupGap([3,0]) # optional - gap_packages Abelian group with gap, generator orders (3, 0)
AUTHORS:
- Simon Brandhorst (2018-01-17): initial version """
# **************************************************************************** # Copyright (C) 2018 Simon Brandhorst <sbrandhorst@web.de> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ # ****************************************************************************
r""" An element of an abelian group via libgap.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3,6]) sage: G.gens() (f1, f2) """ """ The Python constructor.
See :class:`AbelianGroupElement_gap` for details.
INPUT:
- ``parent`` -- an instance of :class:`AbelianGroup_gap` - ``x`` -- an instance of :class:`sage.libs.gap.element.GapElement` - ``check`` -- boolean (default: ``True``); check if ``x`` is an element of the group
TESTS::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3,6]) sage: g = G.an_element() sage: TestSuite(g).run() """
r""" Return the hash of this element.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3,2,4]) sage: g = G.an_element() sage: g.__hash__() # random 1693277541873681615 """
r""" Implement pickling.
OUTPUT:
- a tuple ``f`` such that this element is ``f[0](*f[1])``
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3,2,4]) sage: g = G.an_element() sage: g == loads(dumps(g)) True sage: g.__reduce__() (Abelian group with gap, generator orders (3, 2, 4), ((1, 1, 1),)) """
r""" Return the tuple of exponents of this element.
OUTPUT:
- a tuple of integers
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([4,7,9]) sage: gens = G.gens() sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8 sage: g.exponents() (2, 4, 8) sage: S = G.subgroup(G.gens()[:1]) sage: s = S.gens()[0] sage: s f1 sage: s.exponents() (1,)
It can handle quite large groups too::
sage: G = AbelianGroupGap([2^10, 5^10]) sage: f1, f2 = G.gens() sage: g = f1^123*f2^789 sage: g.exponents() (123, 789)
.. WARNING::
Crashes for very large groups.
.. TODO::
Make exponents work for very large groups. This could be done by using Pcgs in gap. """
# better than Factorization as this does not create the # whole group in memory. else:
r""" Return the order of this element.
OUTPUT:
- an integer or infinity
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([4]) sage: g = G.gens()[0] sage: g.order() 4 sage: G = AbelianGroupGap([0]) # optional - gap_packages sage: g = G.gens()[0] # optional - gap_packages sage: g.order() # optional - gap_packages +Infinity """
r""" An element of an abelian group using the GAP package ``Polycyclic``.
TESTS::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([4,7,0]) # optional - gap_packages sage: TestSuite(G.an_element()).run() # optional - gap_packages """ r""" Return the tuple of exponents of ``self``.
OUTPUT:
- a tuple of integers
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([4,7,0]) # optional - gap_packages sage: gens = G.gens() # optional - gap_packages sage: g = gens[0]^2 * gens[1]^4 * gens[2]^8 # optional - gap_packages sage: g.exponents() # optional - gap_packages (2, 4, 8)
Efficiently handles very large groups::
sage: G = AbelianGroupGap([2^30,5^30,0]) # optional - gap_packages sage: f1, f2, f3 = G.gens() # optional - gap_packages sage: (f1^12345*f2^123456789).exponents() # optional - gap_packages (12345, 123456789, 0) """ return tuple(self.gap().Exponents().sage())
r""" Finitely generated abelian groups implemented in GAP.
Needs the gap package ``Polycyclic`` in case the group is infinite.
INPUT:
- ``G`` -- a GAP group - ``category`` -- a category - ``ambient`` -- (optional) an :class:`AbelianGroupGap`
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3, 2, 5]) sage: G Abelian group with gap, generator orders (3, 2, 5) """ r""" Create an instance of this class.
See :class:`AbelianGroup_gap` for details
TESTS::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3,2,5]) sage: TestSuite(G).run() """
r""" Return whether ``S`` canonically coerces to ``self``.
INPUT:
- ``S`` -- anything
OUTPUT:
Boolean.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: gen = G.gens()[:2] sage: S = G.subgroup(gen) sage: G._coerce_map_from_(S) True sage: S._coerce_map_from_(G) False """
r""" Defines coercions and conversions.
INPUT:
- ``x`` -- an element of this group, a GAP element
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3]) sage: A = AbelianGroup([2,3]) sage: a = A.an_element() sage: a f0*f1 sage: G(a) f1*f2 sage: A = AdditiveAbelianGroup([2,3]) sage: a = A.an_element() sage: a (1, 0) sage: G(a) f1
For general ``fgp_modules`` conversion is implemented if our group is in Smith form::
sage: G = AbelianGroupGap([6]) sage: A = ZZ^2 sage: e0,e1 = A.gens() sage: A = A / A.submodule([2*e0, 3*e1]) sage: a = 2 * A.an_element() sage: a (2) sage: G(a) f2 """ else: # turn the exponents into a gap element
r""" Return the list of all subgroups of this group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2, 3]) sage: G.all_subgroups() [Subgroup of Abelian group with gap, generator orders (2, 3) generated by (1,), Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f1,), Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f2,), Subgroup of Abelian group with gap, generator orders (2, 3) generated by (f1, f2)] """
r""" Return the group of automorphisms of ``self``.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2, 3]) sage: G.aut() Full group of automorphisms of Abelian group with gap, generator orders (2, 3) """
r""" Return ``True`` if this group is the trivial group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([]) sage: G Abelian group with gap, generator orders () sage: G.is_trivial() True sage: AbelianGroupGap([1]).is_trivial() True sage: AbelianGroupGap([1,1,1]).is_trivial() True sage: AbelianGroupGap([2]).is_trivial() False sage: AbelianGroupGap([2,1]).is_trivial() False """
r""" Return the identity element of this group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([4,10]) sage: G.identity() 1 """
def elementary_divisors(self): r""" Return the elementary divisors of this group.
See :meth:`sage.groups.abelian_gps.abelian_group_gap.elementary_divisors`.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: G.elementary_divisors() (2, 60) """
def exponent(self): r""" Return the exponent of this abelian group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,7]) sage: G Abelian group with gap, generator orders (2, 3, 7) sage: G = AbelianGroupGap([2,4,6]) sage: G Abelian group with gap, generator orders (2, 4, 6) sage: G.exponent() 12 """
def gens_orders(self): r""" Return the orders of the generators.
Use :meth:`elementary_divisors` if you are looking for an invariant of the group.
OUTPUT:
- a tuple of integers
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: Z2xZ3 = AbelianGroupGap([2,3]) sage: Z2xZ3.gens_orders() (2, 3) sage: Z2xZ3.elementary_divisors() (6,) sage: Z6 = AbelianGroupGap([6]) sage: Z6.gens_orders() (6,) sage: Z6.elementary_divisors() (6,) sage: Z2xZ3.is_isomorphic(Z6) True sage: Z2xZ3 is Z6 False """ order = 0
r""" Return if ``self`` is a subgroup of ``G`` considered in the same ambient group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: gen = G.gens()[:2] sage: S1 = G.subgroup(gen) sage: S1.is_subgroup_of(G) True sage: S2 = G.subgroup(G.gens()[1:]) sage: S2.is_subgroup_of(S1) False """ raise ValueError("input must be an instance of AbelianGroup_gap") return False
r""" Return the subgroup of this group generated by ``gens``.
INPUT:
- ``gens`` -- a list of elements coercible into this group
OUTPUT:
- a subgroup
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: gen = G.gens()[:2] sage: S = G.subgroup(gen) sage: S Subgroup of Abelian group with gap, generator orders (2, 3, 4, 5) generated by (f1, f2) sage: g = G.an_element() sage: s = S.an_element() sage: g * s f2^2*f3*f5 sage: G = AbelianGroupGap([3,4,0,2]) # optional - gap_packages sage: gen = G.gens()[:2] # optional - gap_packages sage: S = G.subgroup(gen) # optional - gap_packages sage: g = G.an_element() # optional - gap_packages sage: s = S.an_element() # optional - gap_packages sage: g * s # optional - gap_packages g1^2*g2^2*g3*g4
TESTS::
sage: h = G.gens()[3] sage: h in S False """
r""" Abelian groups implemented using GAP.
INPUT:
- ``generator_orders`` -- a list of nonnegative integers where `0` gives a factor isomorphic to `\ZZ`
OUTPUT:
- an abelian group
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: AbelianGroupGap([3,6]) Abelian group with gap, generator orders (3, 6) sage: AbelianGroupGap([3,6,5]) Abelian group with gap, generator orders (3, 6, 5) sage: AbelianGroupGap([3,6,0]) # optional - gap_packages Abelian group with gap, generator orders (3, 6, 0)
.. WARNING::
Needs the GAP package ``Polycyclic`` in case the group is infinite. """ def __classcall_private__(cls, generator_orders): r""" Normalize input to ensure a unique representation.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: A1 = AbelianGroupGap((2,3,4)) sage: A2 = AbelianGroupGap([4/2,3,4]) sage: A1 is A2 True """ return ValueError("generator orders must be nonnegative")
r""" Constructor.
TESTS::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: A = AbelianGroup((2,3,4)) sage: TestSuite(A).run() """ if not libgap.LoadPackage("Polycyclic"): raise ImportError("unable to import polycyclic package") G = libgap.eval("AbelianPcpGroup(%s)" % list(generator_orders)) category = category.Infinite() self.Element = AbelianGroupElement_polycyclic else:
""" Return a latex representation of this group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,6]) sage: G._latex_() 'Abelian group with gap, generator orders $(2, 6)$' """
r""" Return a string representation of this group.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,6]) sage: G._repr_() 'Abelian group with gap, generator orders (2, 6)' """
r""" Implements pickling.
We have to work around the fact that gap does not provide pickling.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([3,2,5]) sage: G == loads(dumps(G)) True sage: G is loads(dumps(G)) True """
r""" Subgroups of abelian groups with GAP.
INPUT:
- ``ambient`` -- the ambient group - ``gens`` -- generators of the subgroup
.. NOTE::
Do not construct this class directly. Instead use :meth:`~sage.groups.abelian_groups.AbelianGroupGap.subgroup`.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: gen = G.gens()[:2] sage: S = G.subgroup(gen) """ r""" Initialize this subgroup.
TESTS::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap, AbelianGroupSubgroup_gap sage: G = AbelianGroupGap([]) sage: gen = G.gens() sage: A = AbelianGroupSubgroup_gap(G, gen) sage: TestSuite(A).run()
Check that we are in the correct category::
sage: G = AbelianGroupGap([2,3,0]) # optional - gap_packages sage: g = G.gens() # optional - gap_packages sage: H1 = G.subgroup([g[0],g[1]]) # optional - gap_packages sage: H1 in Groups().Finite() # optional - gap_packages True sage: H2 = G.subgroup([g[0],g[2]]) # optional - gap_packages sage: H2 in Groups().Infinite() # optional - gap_packages True """ else: category = category.Infinite() # FIXME: Tell the category that it is a Subobjects() category # category = category.Subobjects()
r""" Return a string representation of this subgroup.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: gen = G.gens()[:2] sage: S = G.subgroup(gen) sage: S Subgroup of Abelian group with gap, generator orders (2, 3, 4, 5) generated by (f1, f2) """
r""" Implements pickling.
We have to work around the fact that gap does not provide pickling.
EXAMPLES::
sage: from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap sage: G = AbelianGroupGap([2,3,4,5]) sage: gen = G.gens()[:2] sage: S = G.subgroup(gen) sage: S == loads(dumps(S)) True sage: S is loads(dumps(S)) True """ # avoid infinite loop
|