Path: blob/master/src/sage/groups/abelian_gps/values.py
8815 views
"""1Multiplicative Abelian Groups With Values23Often, one ends up with a set that forms an Abelian group. It would be4nice if one could return an Abelian group class to encapsulate the5data. However,6:func:`~sage.groups.abelian_gps.abelian_group.AbelianGroup` is an7abstract Abelian group defined by generators and relations. This8module implements :class:`AbelianGroupWithValues` that allows the9group elements to be decorated with values.1011An example where this module is used is the unit group of a number12field, see :mod:`sage.rings.number_field.unit_group`. The units form a13finitely generated Abelian group. We can think of the elements either14as abstract Abelian group elements or as particular numbers in the15number field. The :func:`AbelianGroupWithValues` keeps track of these16associated values.1718.. warning::1920Really, this requires a group homomorphism from the abstract21Abelian group to the set of values. This is only checked if you22pass the ``check=True`` option to :func:`AbelianGroupWithValues`.2324EXAMPLES:2526Here is `\ZZ_6` with value `-1` assigned to the generator::2728sage: Z6 = AbelianGroupWithValues([-1], [6], names='g')29sage: g = Z6.gen(0)30sage: g.value()31-132sage: g*g33g^234sage: (g*g).value()35136sage: for i in range(7):37... print i, g^i, (g^i).value()380 1 1391 g -1402 g^2 1413 g^3 -1424 g^4 1435 g^5 -1446 1 14546The elements come with a coercion embedding into the47:meth:`~AbelianGroupWithValues_class.values_group`, so you can use the48group elements instead of the values::4950sage: CF3.<zeta> = CyclotomicField(3)51sage: Z3.<g> = AbelianGroupWithValues([zeta], [3])52sage: Z3.values_group()53Cyclotomic Field of order 3 and degree 254sage: g.value()55zeta56sage: CF3(g)57zeta58sage: g + zeta592*zeta60sage: zeta + g612*zeta62"""6364##########################################################################65# Copyright (C) 2012 Volker Braun <[email protected]>66#67# Distributed under the terms of the GNU General Public License (GPL):68#69# http://www.gnu.org/licenses/70##########################################################################717273from sage.misc.misc import prod74from sage.rings.integer import Integer75from sage.categories.morphism import Morphism76from sage.groups.abelian_gps.abelian_group import AbelianGroup_class, _normalize77from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement78798081def AbelianGroupWithValues(values, n, gens_orders=None, names='f', check=False, values_group=None):82"""83Construct an Abelian group with values associated to the generators.8485INPUT:8687- ``values`` -- a list/tuple/iterable of values that you want to88associate to the generators.8990- ``n`` -- integer (optional). If not specified, will be derived91from ``gens_orders``.9293- ``gens_orders`` -- a list of non-negative integers in the form94`[a_0, a_1, \dots, a_{n-1}]`, typically written in increasing95order. This list is padded with zeros if it has length less96than n. The orders of the commuting generators, with `0`97denoting an infinite cyclic factor.9899- ``names`` -- (optional) names of generators100101- ``values_group`` -- a parent or ``None`` (default). The common102parent of the values. This might be a group, but can also just103contain the values. For example, if the values are units in a104ring then the ``values_group`` would be the whole ring. If105``None`` it will be derived from the values.106107EXAMPLES::108109sage: G = AbelianGroupWithValues([-1], [6])110sage: g = G.gen(0)111sage: for i in range(7):112... print i, g^i, (g^i).value()1130 1 11141 f -11152 f^2 11163 f^3 -11174 f^4 11185 f^5 -11196 1 1120sage: G.values_group()121Integer Ring122123The group elements come with a coercion embedding into the124:meth:`values_group`, so you can use them like their125:meth:`~sage.groups.abelian_gps.value.AbelianGroupWithValuesElement.value`126::127128sage: G.values_embedding()129Generic morphism:130From: Multiplicative Abelian group isomorphic to C6131To: Integer Ring132sage: g.value()133-1134sage: 0 + g135-1136sage: 1 + 2*g137-1138"""139if check:140raise NotImplementedError('checking that the values are a homomorphism is not implemented')141gens_orders, names = _normalize(n, gens_orders, names)142if values_group is None:143from sage.structure.sequence import Sequence144values_group = Sequence(values).universe()145values = tuple( values_group(val) for val in values )146M = AbelianGroupWithValues_class(gens_orders, names, values, values_group)147return M148149150class AbelianGroupWithValuesEmbedding(Morphism):151"""152The morphism embedding the Abelian group with values in its values group.153154INPUT:155156- ``domain`` -- a :class:`AbelianGroupWithValues_class`157158- ``codomain`` -- the values group (need not be in the cateory of159groups, e.g. symbolic ring).160161EXAMPLES::162163sage: Z4.<g> = AbelianGroupWithValues([I], [4])164sage: embedding = Z4.values_embedding(); embedding165Generic morphism:166From: Multiplicative Abelian group isomorphic to C4167To: Symbolic Ring168sage: embedding(1)1691170sage: embedding(g)171I172sage: embedding(g^2)173-1174"""175176def __init__(self, domain, codomain):177"""178Construct the morphism179180TESTS::181182sage: Z4 = AbelianGroupWithValues([I], [4])183sage: from sage.groups.abelian_gps.values import AbelianGroupWithValuesEmbedding184sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group())185Generic morphism:186From: Multiplicative Abelian group isomorphic to C4187To: Symbolic Ring188"""189assert domain.values_group() is codomain190from sage.categories.homset import Hom191Morphism.__init__(self, Hom(domain, codomain))192193def _call_(self, x):194"""195Return the value associated to ``x``196197INPUT:198199- ``x`` -- a group element200201OUTPUT:202203Its value.204205EXAMPLES::206207sage: Z4.<g> = AbelianGroupWithValues([I], [4])208sage: embedding = Z4.values_embedding()209sage: embedding(g)210I211sage: embedding._call_(g)212I213"""214return x.value()215216217class AbelianGroupWithValuesElement(AbelianGroupElement):218"""219An element of an Abelian group with values assigned to generators.220221INPUT:222223- ``exponents`` -- tuple of integers. The exponent vector defining224the group element.225226- ``parent`` -- the parent.227228- ``value`` -- the value assigned to the group element or ``None``229(default). In the latter case, the value is computed as needed.230231EXAMPLES::232233sage: F = AbelianGroupWithValues([1,-1], [2,4])234sage: a,b = F.gens()235sage: TestSuite(a*b).run()236"""237238def __init__(self, parent, exponents, value=None):239"""240Create an element241242EXAMPLES::243244sage: F = AbelianGroupWithValues([1,-1], [2,4])245sage: a,b = F.gens()246sage: a*b^-1 in F247True248sage: (a*b^-1).value()249-1250"""251self._value = value252AbelianGroupElement.__init__(self, parent, exponents)253254def value(self):255"""256Return the value of the group element.257258OUTPUT:259260The value according to the values for generators, see261:meth:`~AbelianGroupWithValues.gens_values`.262263EXAMPLES::264265sage: G = AbelianGroupWithValues([5], 1)266sage: G.0.value()2675268"""269if self._value is None:270values = self.parent().gens_values()271self._value = prod( v**e for v,e in zip(values, self.exponents()) )272return self._value273274def _div_(left, right):275"""276Divide ``left`` by ``right``277278TESTS::279280sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)281sage: a._div_(b)282a*b^-1283sage: a/b284a*b^-1285sage: (a/b).value()2865/2287"""288m = AbelianGroupElement._div_(left, right)289m._value = left.value() / right.value()290return m291292def _mul_(left, right):293"""294Multiply ``left`` and ``right``295296TESTS::297298sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)299sage: a._mul_(b)300a*b301sage: a*b302a*b303sage: (a*b).value()30410305"""306m = AbelianGroupElement._mul_(left, right)307m._value = left.value() * right.value()308return m309310def __pow__(self, n):311"""312Exponentiate ``self``313314INPUT:315316- ``n`` -- integer. The exponent.317318TESTS::319320sage: G.<a,b> = AbelianGroupWithValues([5,2], 2)321sage: a^3322a^3323sage: (a^3).value()324125325"""326m = Integer(n)327if n != m:328raise TypeError('argument n (= '+str(n)+') must be an integer.')329pow_self = AbelianGroupElement.__pow__(self, m)330pow_self._value = pow(self.value(), m)331return pow_self332333def inverse(self):334"""335Return the inverse element.336337EXAMPLE::338339sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])340sage: a.inverse()341a^-1342sage: a.inverse().value()3431/2344sage: a.__invert__().value()3451/2346sage: (~a).value()3471/2348sage: (a*b).value()349-2350sage: (a*b).inverse().value()351-1/2352"""353m = AbelianGroupElement.inverse(self)354m._value = ~self.value()355return m356357__invert__ = inverse358359360361class AbelianGroupWithValues_class(AbelianGroup_class):362"""363The class of an Abelian group with values associated to the generator.364365INPUT:366367- ``generator_orders`` -- tuple of integers. The orders of the368generators.369370- ``names`` -- string or list of strings. The names for the generators.371372- ``values`` -- Tuple the same length as the number of373generators. The values assigned to the generators.374375- ``values_group`` -- the common parent of the values.376377EXAMPLES::378379sage: G.<a,b> = AbelianGroupWithValues([2,-1], [0,4])380sage: TestSuite(G).run()381"""382Element = AbelianGroupWithValuesElement383384def __init__(self, generator_orders, names, values, values_group):385"""386The Python constructor387388TESTS::389390sage: G = AbelianGroupWithValues([2,-1], [0,4]); G391Multiplicative Abelian group isomorphic to Z x C4392393sage: cm = sage.structure.element.get_coercion_model()394sage: cm.explain(G, ZZ, operator.add)395Coercion on left operand via396Generic morphism:397From: Multiplicative Abelian group isomorphic to Z x C4398To: Integer Ring399Arithmetic performed after coercions.400Result lives in Integer Ring401Integer Ring402"""403self._values = values404self._values_group = values_group405AbelianGroup_class.__init__(self, generator_orders, names)406self._populate_coercion_lists_(embedding=self.values_embedding())407if self.ngens() != len(self._values):408raise ValueError('need one value per generator')409410def gen(self, i=0):411"""412The `i`-th generator of the abelian group.413414INPUT:415416- ``i`` -- integer (default: 0). The index of the generator.417418OUTPUT:419420A group element.421422EXAMPLES::423424sage: F = AbelianGroupWithValues([1,2,3,4,5], 5,[],names='a')425sage: F.0426a0427sage: F.0.value()4281429sage: F.2430a2431sage: F.2.value()4323433434sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])435sage: G.gens()436(f0, 1, f2)437"""438g = AbelianGroup_class.gen(self, i)439g._value = self._values[i]440return g441442def gens_values(self):443"""444Return the values associated to the generators.445446OUTPUT:447448A tuple.449450EXAMPLES::451452sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])453sage: G.gens()454(f0, 1, f2)455sage: G.gens_values()456(-1, 0, 1)457"""458return self._values459460def values_group(self):461"""462The common parent of the values.463464The values need to form a multiplicative group, but can be465embedded in a larger structure. For example, if the values are466units in a ring then the :meth:`values_group` would be the467whole ring.468469OUTPUT:470471The common parent of the values, containing the group472generated by all values.473474EXAMPLES::475476sage: G = AbelianGroupWithValues([-1,0,1], [2,1,3])477sage: G.values_group()478Integer Ring479480sage: Z4 = AbelianGroupWithValues([I], [4])481sage: Z4.values_group()482Symbolic Ring483"""484return self._values_group485486def values_embedding(self):487"""488Return the embedding of ``self`` in :meth:`values_group`.489490OUTPUT:491492A morphism.493494EXAMPLES::495496sage: Z4 = AbelianGroupWithValues([I], [4])497sage: Z4.values_embedding()498Generic morphism:499From: Multiplicative Abelian group isomorphic to C4500To: Symbolic Ring501"""502return AbelianGroupWithValuesEmbedding(self, self.values_group())503504505