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""" Wrapper class for abelian groups
This class is intended as a template for anything in Sage that needs the functionality of abelian groups. One can create an AdditiveAbelianGroupWrapper object from any given set of elements in some given parent, as long as an ``_add_`` method has been defined.
EXAMPLES:
We create a toy example based on the Mordell-Weil group of an elliptic curve over `\QQ`::
sage: E = EllipticCurve('30a2') sage: pts = [E(4,-7,1), E(7/4, -11/8, 1), E(3, -2, 1)] sage: M = AdditiveAbelianGroupWrapper(pts[0].parent(), pts, [3, 2, 2]) sage: M Additive abelian group isomorphic to Z/3 + Z/2 + Z/2 embedded in Abelian group of points on Elliptic Curve defined by y^2 + x*y + y = x^3 - 19*x + 26 over Rational Field sage: M.gens() ((4 : -7 : 1), (7/4 : -11/8 : 1), (3 : -2 : 1)) sage: 3*M.0 (0 : 1 : 0) sage: 3000000000000001 * M.0 (4 : -7 : 1) sage: M == loads(dumps(M)) # known bug, see http://trac.sagemath.org/sage_trac/ticket/11599#comment:7 True
We check that ridiculous operations are being avoided::
sage: set_verbose(2, 'additive_abelian_wrapper.py') sage: 300001 * M.0 verbose 1 (...: additive_abelian_wrapper.py, _discrete_exp) Calling discrete exp on (1, 0, 0) (4 : -7 : 1) sage: set_verbose(0, 'additive_abelian_wrapper.py')
TODO:
- Implement proper black-box discrete logarithm (using baby-step giant-step). The discrete_exp function can also potentially be speeded up substantially via caching.
- Think about subgroups and quotients, which probably won't work in the current implementation -- some fiddly adjustments will be needed in order to be able to pass extra arguments to the subquotient's init method. """ from __future__ import absolute_import
from . import additive_abelian_group as addgp from sage.rings.all import ZZ from sage.misc.misc import verbose from sage.categories.morphism import Morphism from sage.structure.element import parent
class UnwrappingMorphism(Morphism): r""" The embedding into the ambient group. Used by the coercion framework. """ def __init__(self, domain): r""" EXAMPLES::
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) sage: F = QQbar.coerce_map_from(G); F Generic morphism: From: Additive abelian group isomorphic to Z + Z embedded in Algebraic Field To: Algebraic Field sage: type(F) <class 'sage.groups.additive_abelian.additive_abelian_wrapper.UnwrappingMorphism'> """
def _call_(self, x): r""" TESTS::
sage: E = EllipticCurve("65a1") sage: G = E.torsion_subgroup() sage: isinstance(G, sage.groups.additive_abelian.additive_abelian_wrapper.AdditiveAbelianGroupWrapper) True sage: P1 = E([1,-1,1]) sage: P2 = E([0,1,0]) sage: P1 in G # indirect doctest False sage: P2 in G True sage: (G(P2) + P1) in G False sage: (G(P2) + P1).parent() Abelian group of points on Elliptic Curve defined by y^2 + x*y = x^3 - x over Rational Field """
class AdditiveAbelianGroupWrapperElement(addgp.AdditiveAbelianGroupElement): """ An element of an :class:`AdditiveAbelianGroupWrapper`. """
def __init__(self, parent, vector, element=None, check=False): r""" EXAMPLES:
sage: from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) sage: G.0 # indirect doctest 1.414213562373095? """
def element(self): r""" Return the underlying object that this element wraps.
EXAMPLES::
sage: T = EllipticCurve('65a').torsion_subgroup().gen(0) sage: T; type(T) (0 : 0 : 1) <class 'sage.schemes.elliptic_curves.ell_torsion.EllipticCurveTorsionSubgroup_with_category.element_class'> sage: T.element(); type(T.element()) (0 : 0 : 1) <class 'sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_number_field'> """
def _repr_(self): r""" String representation of self.
EXAMPLES::
sage: T = EllipticCurve('65a').torsion_subgroup().gen(0) sage: repr(T) # indirect doctest '(0 : 0 : 1)' """
class AdditiveAbelianGroupWrapper(addgp.AdditiveAbelianGroup_fixed_gens): """ The parent of :class:`AdditiveAbelianGroupWrapperElement` """
Element = AdditiveAbelianGroupWrapperElement
def __init__(self, universe, gens, invariants): r""" EXAMPLES::
sage: AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) # indirect doctest Additive abelian group isomorphic to Z + Z embedded in Algebraic Field """
def universe(self): r""" The ambient group in which this abelian group lives.
EXAMPLES::
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) sage: G.universe() Algebraic Field """
def generator_orders(self): r""" The orders of the generators with which this group was initialised. (Note that these are not necessarily a minimal set of generators.) Generators of infinite order are returned as 0. Compare ``self.invariants()``, which returns the orders of a minimal set of generators.
EXAMPLES::
sage: V = Zmod(6)**2 sage: G = AdditiveAbelianGroupWrapper(V, [2*V.0, 3*V.1], [3, 2]) sage: G.generator_orders() (3, 2) sage: G.invariants() (6,) """
def _repr_(self): r""" EXAMPLES::
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) sage: repr(G) # indirect doctest 'Additive abelian group isomorphic to Z + Z embedded in Algebraic Field' """
def _discrete_exp(self, v): r""" Given a list (or other iterable) of length equal to the number of generators of this group, compute the element of the ambient group with those exponents in terms of the generators of self.
EXAMPLES::
sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), -1], [0, 0]) sage: v = G._discrete_exp([3, 5]); v -0.7573593128807148? sage: v.parent() is QQbar True """ # DUMB IMPLEMENTATION!
def _discrete_log(self,x): r""" Given an element of the ambient group, attempt to express it in terms of the generators of self.
EXAMPLES::
sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2]) sage: G._discrete_log(V([6, 2])) (1, 1) sage: G._discrete_log(V([6, 4])) Traceback (most recent call last): ... TypeError: Not in group sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(2)], [0]) sage: G._discrete_log(QQbar(2*sqrt(2))) Traceback (most recent call last): ... NotImplementedError: No black-box discrete log for infinite abelian groups """ # EVEN DUMBER IMPLEMENTATION!
def _element_constructor_(self, x, check=False): r""" Create an element from x. This may be either an element of self, an element of the ambient group, or an iterable (in which case the result is the corresponding product of the generators of self).
EXAMPLES::
sage: V = Zmod(8)**2; G = AdditiveAbelianGroupWrapper(V, [[2,2],[4,0]], [4, 2]) sage: G(V([6,2])) (6, 2) sage: G([1,1]) doctest:...: DeprecationWarning: The default behaviour changed! If you *really* want a linear combination of smith generators, use .linear_combination_of_smith_form_gens. See http://trac.sagemath.org/16261 for details. (6, 2) sage: G(G([1,1])) (6, 2) """
|