Path: blob/master/sage/groups/additive_abelian/additive_abelian_wrapper.py
4094 views
r"""1Wrapper class for abelian groups23This class is intended as a template for anything in Sage that needs the4functionality of abelian groups. One can create an AdditiveAbelianGroupWrapper5object from any given set of elements in some given parent, as long as an6``_add_`` method has been defined.789EXAMPLES:1011We create a toy example based on the Mordell-Weil group of an elliptic curve over `\QQ`::1213sage: E = EllipticCurve('30a2')14sage: pts = [E(4,-7,1), E(7/4, -11/8, 1), E(3, -2, 1)]15sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [3, 2, 2])16sage: M17Additive abelian group isomorphic to Z/2 + Z/6 embedded in Abelian group of18points on Elliptic Curve defined by y^2 + x*y + y = x^3 - 19*x + 26 over19Rational Field20sage: M.gens()21((4 : -7 : 1), (7/4 : -11/8 : 1), (3 : -2 : 1))22sage: 3*M.023(0 : 1 : 0)24sage: 3000000000000001 * M.025(4 : -7 : 1)26sage: M == loads(dumps(M)) # optional - pickling http://trac.sagemath.org/sage_trac/ticket/1159927True2829We check that ridiculous operations are being avoided::3031sage: set_verbose(2, 'additive_abelian_wrapper.py')32sage: 300001 * M.033verbose 1 (...: additive_abelian_wrapper.py, _discrete_exp) Calling discrete exp on (1, 0, 0)34(4 : -7 : 1)35sage: set_verbose(0, 'additive_abelian_wrapper.py')363738TODO:3940- Implement proper black-box discrete logarithm (using baby-step giant-step).41The discrete_exp function can also potentially be speeded up substantially42via caching.4344- Think about subgroups and quotients, which probably won't work in the current45implementation -- some fiddly adjustments will be needed in order to be able46to pass extra arguments to the subquotient's init method.47"""4849import additive_abelian_group as addgp50from sage.rings.all import ZZ51from sage.misc.misc import verbose52from sage.categories.morphism import Morphism5354class UnwrappingMorphism(Morphism):55r"""56The embedding into the ambient group. Used by the coercion framework.57"""58def __init__(self, domain):59r"""60EXAMPLE::6162sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])63sage: F = QQbar.coerce_map_from(G); F64Generic morphism:65From: Additive abelian group isomorphic to Z + Z embedded in Algebraic Field66To: Algebraic Field67sage: type(F)68<class 'sage.groups.additive_abelian.additive_abelian_wrapper.UnwrappingMorphism'>69"""70Morphism.__init__(self, domain.Hom(domain.universe()))7172def _call_(self, x):73r"""74TEST::7576sage: E = EllipticCurve("65a1")77sage: G = E.torsion_subgroup()78sage: isinstance(G, sage.groups.additive_abelian.additive_abelian_wrapper.AdditiveAbelianGroupWrapper)79True80sage: P1 = E([1,-1,1])81sage: P2 = E([0,1,0])82sage: P1 in G # indirect doctest83False84sage: P2 in G85True86sage: (G(P2) + P1) in G87False88sage: (G(P2) + P1).parent()89Abelian group of points on Elliptic Curve defined by y^2 + x*y = x^3 - x over Rational Field90"""91return self.codomain()(x.element())929394class AdditiveAbelianGroupWrapperElement(addgp.AdditiveAbelianGroupElement):95"""96An element of an :class:`AdditiveAbelianGroupWrapper`.97"""9899def __init__(self, parent, vector, element=None, check=False):100r"""101EXAMPLE:102103sage: from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper104sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])105sage: G.0 # indirect doctest1061.414213562373095?107"""108addgp.AdditiveAbelianGroupElement.__init__(self, parent, vector, check)109if element is not None:110element = self.parent().universe()(element)111self._element = element112113def element(self):114r"""115Return the underlying object that this element wraps.116117EXAMPLE::118119sage: T = EllipticCurve('65a').torsion_subgroup().gen(0)120sage: T; type(T)121(0 : 0 : 1)122<class 'sage.groups.additive_abelian.additive_abelian_wrapper.EllipticCurveTorsionSubgroup_with_category.element_class'>123sage: T.element(); type(T.element())124(0 : 0 : 1)125<class 'sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_number_field'>126"""127if self._element is None:128self._element = self.parent()._discrete_exp(self._hermite_lift())129return self._element130131def _repr_(self):132r"""133String representation of self.134135EXAMPLE::136137sage: T = EllipticCurve('65a').torsion_subgroup().gen(0)138sage: repr(T) # indirect doctest139'(0 : 0 : 1)'140"""141return repr(self.element())142143144class AdditiveAbelianGroupWrapper(addgp.AdditiveAbelianGroup_fixed_gens):145"""146The parent of :class:`AdditiveAbelianGroupWrapperElement`147"""148149Element = AdditiveAbelianGroupWrapperElement150151def __init__(self, universe, gens, invariants):152r"""153EXAMPLE::154155sage: AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) # indirect doctest156Additive abelian group isomorphic to Z + Z embedded in Algebraic Field157"""158self._universe = universe159self._gen_elements = tuple(universe(x) for x in gens)160self._gen_orders = invariants161cover,rels = addgp.cover_and_relations_from_invariants(invariants)162addgp.AdditiveAbelianGroup_fixed_gens.__init__(self, cover, rels, cover.gens())163self._unset_coercions_used()164self.register_embedding(UnwrappingMorphism(self))165166def universe(self):167r"""168The ambient group in which this abelian group lives.169170EXAMPLE::171172sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])173sage: G.universe()174Algebraic Field175"""176return self._universe177178def generator_orders(self):179r"""180The orders of the generators with which this group was initialised.181(Note that these are not necessarily a minimal set of generators.)182Generators of infinite order are returned as 0. Compare183``self.invariants()``, which returns the orders of a minimal set of184generators.185186EXAMPLE::187188sage: V = Zmod(6)**2189sage: G = AdditiveAbelianGroupWrapper(V, [2*V.0, 3*V.1], [3, 2])190sage: G.generator_orders()191(3, 2)192sage: G.invariants()193(6,)194"""195return tuple(self._gen_orders)196197def _repr_(self):198r"""199EXAMPLE::200201sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0])202sage: repr(G) # indirect doctest203'Additive abelian group isomorphic to Z + Z embedded in Algebraic Field'204"""205return addgp.AdditiveAbelianGroup_fixed_gens._repr_(self) + " embedded in " + self.universe()._repr_()206207def _discrete_exp(self, v):208r"""209Given a list (or other iterable) of length equal to the number of210generators of this group, compute the element of the ambient group with211those exponents in terms of the generators of self.212213EXAMPLE::214215sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), -1], [0, 0])216sage: v = G._discrete_exp([3, 5]); v217-0.7573593128807148?218sage: v.parent() is QQbar219True220"""221v = self.V()(v)222verbose("Calling discrete exp on %s" % v)223# DUMB IMPLEMENTATION!224return sum([self._gen_elements[i] * ZZ(v[i]) for i in xrange(len(v))], self.universe()(0))225226def _discrete_log(self,x):227r"""228Given an element of the ambient group, attempt to express it in terms of the229generators of self.230231EXAMPLE::232233sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2])234sage: G._discrete_log(V([6, 2]))235(1, 1)236sage: G._discrete_log(V([6, 4]))237Traceback (most recent call last):238...239TypeError: Not in group240sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(2)], [0])241sage: G._discrete_log(QQbar(2*sqrt(2)))242Traceback (most recent call last):243...244NotImplementedError: No black-box discrete log for infinite abelian groups245"""246# EVEN DUMBER IMPLEMENTATION!247from sage.rings.infinity import Infinity248if self.order() == Infinity:249raise NotImplementedError, "No black-box discrete log for infinite abelian groups"250u = [y for y in self.list() if y.element() == x]251if len(u) == 0: raise TypeError, "Not in group"252if len(u) > 1: raise NotImplementedError253return u[0].vector()254255def _element_constructor_(self, x, check=False):256r"""257Create an element from x. This may be either an element of self, an element of the258ambient group, or an iterable (in which case the result is the corresponding259product of the generators of self).260261EXAMPLES::262263sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2])264sage: G(V([6,2]))265(6, 2)266sage: G([1,1])267(6, 2)268sage: G(G([1,1]))269(6, 2)270"""271if hasattr(x,"parent"):272if x.parent() is self.universe():273return self.element_class(self, self._discrete_log(x), element = x)274return addgp.AdditiveAbelianGroup_fixed_gens._element_constructor_(self, x, check)275276277278