Path: blob/master/sage/groups/additive_abelian/additive_abelian_group.py
4097 views
r"""1Additive Abelian Groups23Additive abelian groups are just modules over `\ZZ`. Hence the classes in this4module derive from those in the module :mod:`sage.modules.fg_pid`. The only5major differences are in the way elements are printed.6"""78from sage.groups.group import AbelianGroup9from sage.modules.fg_pid.fgp_module import FGP_Module_class10from sage.modules.fg_pid.fgp_element import FGP_Element11from sage.rings.all import ZZ1213def AdditiveAbelianGroup(invs, remember_generators = True):14r"""15Construct a finitely-generated additive abelian group.1617INPUTS:1819- ``invs`` (list of integers): the invariants.20These should all be greater than or equal to zero.2122- ``remember_generators`` (boolean): whether or not to fix a set of23generators (corresponding to the given invariants, which need not be in24Smith form).2526OUTPUT:2728The abelian group `\bigoplus_i \ZZ / n_i \ZZ`, where `n_i` are the invariants.2930EXAMPLE::3132sage: AdditiveAbelianGroup([0, 2, 4])33Additive abelian group isomorphic to Z/2 + Z/4 + Z3435An example of the ``remember_generators`` switch::3637sage: G = AdditiveAbelianGroup([0, 2, 3]); G38Additive abelian group isomorphic to Z/6 + Z39sage: G.gens()40((1, 0, 0), (0, 1, 0), (0, 0, 1))4142sage: H = AdditiveAbelianGroup([0, 2, 3], remember_generators = False); H43Additive abelian group isomorphic to Z/6 + Z44sage: H.gens()45((0, 1, 2), (1, 0, 0))4647There are several ways to create elements of an additive abelian group.48Realize that there are two sets of generators: the "obvious" ones composed49of zeros and ones, one for each invariant given to construct the group, the50other being a set of minimal generators. Which set is the default varies51with the use of the ``remember_generators`` switch.5253First with "obvious" generators. Note that a raw list will use the54minimal generators and a vector (a module element) will use the generators55that pair up naturally with the invariants. We create the same element56repeatedly. ::5758sage: H=AdditiveAbelianGroup([3,2,0], remember_generators=True)59sage: H.gens()60((1, 0, 0), (0, 1, 0), (0, 0, 1))61sage: [H.0, H.1, H.2]62[(1, 0, 0), (0, 1, 0), (0, 0, 1)]63sage: p=H.0+H.1+6*H.2; p64(1, 1, 6)6566sage: H.smith_form_gens()67((2, 1, 0), (0, 0, 1))68sage: q=H([5,6]); q69(1, 1, 6)70sage: p==q71True7273sage: r=H(vector([1,1,6])); r74(1, 1, 6)75sage: p==r76True7778sage: s=H(p)79sage: p==s80True8182Again, but now where the generators are the minimal set. Coercing a83list or a vector works as before, but the default generators are different. ::8485sage: G=AdditiveAbelianGroup([3,2,0], remember_generators=False)86sage: G.gens()87((2, 1, 0), (0, 0, 1))88sage: [G.0, G.1]89[(2, 1, 0), (0, 0, 1)]90sage: p=5*G.0+6*G.1; p91(1, 1, 6)9293sage: H.smith_form_gens()94((2, 1, 0), (0, 0, 1))95sage: q=G([5,6]); q96(1, 1, 6)97sage: p==q98True99100sage: r=G(vector([1,1,6])); r101(1, 1, 6)102sage: p==r103True104105sage: s=H(p)106sage: p==s107True108"""109invs = [ZZ(x) for x in invs]110if not all( [x >= 0 for x in invs] ): raise ValueError, "Invariants must be nonnegative"111A, B = cover_and_relations_from_invariants(invs)112if remember_generators:113G = AdditiveAbelianGroup_fixed_gens(A, B, A.gens())114else:115G = AdditiveAbelianGroup_class(A, B)116return G117118def cover_and_relations_from_invariants(invs):119r"""120A utility function to construct modules required to initialize the super class.121122Given a list of integers, this routine constructs the obvious pair of123free modules such that the quotient of the two free modules over `\ZZ`124is naturally isomorphic to the corresponding product of cyclic modules125(and hence isomorphic to a direct sum of cyclic groups).126127EXAMPLES::128129sage: from sage.groups.additive_abelian.additive_abelian_group import cover_and_relations_from_invariants as cr130sage: cr([0,2,3])131(Ambient free module of rank 3 over the principal ideal domain Integer Ring, Free module of degree 3 and rank 2 over Integer Ring132Echelon basis matrix:133[0 2 0]134[0 0 3])135"""136n = len(invs)137A = ZZ**n138B = A.span([A.gen(i) * invs[i] for i in xrange(n)])139return (A, B)140141142143class AdditiveAbelianGroupElement(FGP_Element):144"""145An element of an :class:`AdditiveAbelianGroup_class`.146"""147148def _hermite_lift(self):149r"""150This gives a certain canonical lifting of elements of this group151(represented as a quotient `G/H` of free abelian groups) to `G`, using152the Hermite normal form of the matrix of relations.153154Mainly used by the ``_repr_`` method.155156EXAMPLES::157158sage: A = AdditiveAbelianGroup([2, 3])159sage: v = 3000001 * A.0160sage: v.lift()161(3000001, 0)162sage: v._hermite_lift()163(1, 0)164"""165y = self.lift()166H = self.parent().W().basis_matrix()167pivot_rows = H.pivot_rows()168pivots = H.pivots()169170for i in xrange(H.nrows()):171if i in pivot_rows:172j = pivots[i]173N = H[i,j]174a = (y[j] - (y[j] % N)) // N175y = y - a*H.row(i)176return y177178def _repr_(self):179r"""180String representation. This uses a canonical lifting of elements of181this group (represented as a quotient `G/H` of free abelian groups) to182`G`, using the Hermite normal form of the matrix of relations.183184EXAMPLE::185186sage: G = AdditiveAbelianGroup([2,3])187sage: repr(G.gen(0)) # indirect doctest188'(1, 0)'189sage: a = 13*G.gen(0); repr(a) # indirect doctest190'(1, 0)'191sage: a._x192(13, 0)193"""194return repr(self._hermite_lift())195196197# Note: It's important that the class inherits from FGP_Module_class first,198# since we want to inherit things like __hash__ from there rather than the199# hyper-generic implementation for abstract abelian groups.200201class AdditiveAbelianGroup_class(FGP_Module_class, AbelianGroup):202r"""203An additive abelian group, implemented using the `\ZZ`-module machinery.204205INPUT:206207- ``cover`` -- the covering group as `\ZZ`-module.208209- ``relations`` -- the relations as submodule of ``cover``.210"""211212# The element class must be overridden in derived classes213Element = AdditiveAbelianGroupElement214215def __init__(self, cover, relations):216r"""217EXAMPLE::218219sage: G = AdditiveAbelianGroup([0]); G # indirect doctest220Additive abelian group isomorphic to Z221sage: G == loads(dumps(G))222True223"""224FGP_Module_class.__init__(self, cover, relations)225226def _repr_(self):227r"""228String representation of this group.229230EXAMPLES::231232sage: AdditiveAbelianGroup([0, 2, 3])._repr_()233'Additive abelian group isomorphic to Z/6 + Z'234"""235if self.V().rank() == 0:236return "Trivial group"237else:238return "Additive abelian group isomorphic to %s" % self.short_name()239240def _latex_(self):241r"""242Returns a Latex representation of the group, using the invariants.243244EXAMPLE::245246sage: G=AdditiveAbelianGroup([66, 77, 0, 0])247sage: G._latex_()248'\\frac{\\ZZ}{11\\ZZ} \\oplus \\frac{\\ZZ}{462\\ZZ} \\oplus \\ZZ \\oplus \\ZZ'249250A trivial group is represented as zero, rather than Z/1Z. ::251252sage: G=AdditiveAbelianGroup([1])253sage: G._latex_()254'0'255"""256inv = self.invariants()257if not inv:258inv = (1,)259terms=[]260for i in range(len(inv)):261if inv[i] == 0:262terms.append('\\ZZ')263elif inv[i] == 1:264terms.append('0')265else:266terms.append('\\frac{\\ZZ}{' + str(inv[i]) + '\\ZZ}')267return ' \\oplus '.join(terms)268269def short_name(self):270r"""271Return a name for the isomorphism class of this group.272273EXAMPLE::274275sage: AdditiveAbelianGroup([0, 2,4]).short_name()276'Z/2 + Z/4 + Z'277sage: AdditiveAbelianGroup([0, 2, 3]).short_name()278'Z/6 + Z'279"""280invs = self.invariants()281if not invs: return "Trivial group"282s = ""283for j in invs:284if j == 0: s += "Z + "285else: s += "Z/%s + " % j286return s[:-3] # drop the final " + "287288def _module_constructor(self, cover, relations):289r"""290Construct quotients of groups.291292INPUT:293294- ``cover`` -- the covering group as `\ZZ`-module.295296- ``relations`` -- the relations as submodule of ``cover``.297298EXAMPLE::299300sage: G = AdditiveAbelianGroup([0, 4, 2]); G301Additive abelian group isomorphic to Z/2 + Z/4 + Z302sage: H = G.submodule([G.1]); H303Additive abelian group isomorphic to Z/4304sage: G/H # indirect test305Additive abelian group isomorphic to Z/2 + Z306sage: G._module_constructor(G.cover(),H.cover()+G.relations())307Additive abelian group isomorphic to Z/2 + Z308"""309return AdditiveAbelianGroup_class(cover, relations)310311def order(self):312r"""313Return the order of this group (an integer or infinity)314315EXAMPLES::316317sage: AdditiveAbelianGroup([2,4]).order()3188319sage: AdditiveAbelianGroup([0, 2,4]).order()320+Infinity321sage: AdditiveAbelianGroup([]).order()3221323"""324return self.cardinality()325326def exponent(self):327r"""328Return the exponent of this group (the smallest positive integer `N`329such that `Nx = 0` for all `x` in the group). If there is no such330integer, return 0.331332EXAMPLES::333334sage: AdditiveAbelianGroup([2,4]).exponent()3354336sage: AdditiveAbelianGroup([0, 2,4]).exponent()3370338sage: AdditiveAbelianGroup([]).exponent()3391340"""341if not self.invariants():342return 1343else:344ann = self.annihilator().gen()345if ann:346return ann347return ZZ(0)348349def is_multiplicative(self):350r"""351Return False since this is an additive group.352353EXAMPLE::354355sage: AdditiveAbelianGroup([0]).is_multiplicative()356False357"""358return False359360def is_cyclic(self):361r"""362Returns ``True`` if the group is cyclic.363364EXAMPLES:365366With no common factors between the orders of the generators,367the group will be cyclic. ::368369sage: G=AdditiveAbelianGroup([6, 7, 55])370sage: G.is_cyclic()371True372373Repeating primes in the orders will create a non-cyclic group. ::374375sage: G=AdditiveAbelianGroup([6, 15, 21, 33])376sage: G.is_cyclic()377False378379A trivial group is trivially cyclic. ::380381sage: T=AdditiveAbelianGroup([1])382sage: T.is_cyclic()383True384"""385# One invariant is characteristic of a cyclic group386# while zero invariants is characteristic of the trivial group387return len(self.invariants()) < 2388389390class AdditiveAbelianGroup_fixed_gens(AdditiveAbelianGroup_class):391r"""392A variant which fixes a set of generators, which need not be in Smith form393(or indeed independent).394"""395def __init__(self, cover, rels, gens):396r"""397Standard initialisation function398399EXAMPLE::400401sage: AdditiveAbelianGroup([3]) # indirect doctest402Additive abelian group isomorphic to Z/3403"""404AdditiveAbelianGroup_class.__init__(self, cover, rels)405self._orig_gens = [self(x) for x in gens]406407def gens(self):408r"""409Return the specified generators for self (as a tuple). Compare410``self.smithform_gens()``.411412EXAMPLE::413414sage: G = AdditiveAbelianGroup([2,3])415sage: G.gens()416((1, 0), (0, 1))417sage: G.smith_form_gens()418((1, 2),)419"""420return tuple(self._orig_gens)421422def identity(self):423r"""424Return the identity (zero) element of this group.425426EXAMPLE::427428sage: G = AdditiveAbelianGroup([2, 3])429sage: G.identity()430(0, 0)431"""432return self(0)433434def permutation_group(self):435r"""436Return the permutation group attached to this group.437438EXAMPLE::439440sage: G = AdditiveAbelianGroup([2, 3])441sage: G.permutation_group()442Permutation Group with generators [(1,4,2,5,3,6)]443"""444from sage.groups.perm_gps.permgroup import PermutationGroup445s = 'Image(IsomorphismPermGroup(AbelianGroup(%s)))'%(list(self.invariants()),)446return PermutationGroup(gap_group=s)447448449450