def __init__(self, f): self.f = f self.parameters = Parameters() from sage.symbolic.expression import is_SymbolicEquation if is_SymbolicEquation(f): if f.operator() != operator.eq: raise ValueError, "input to implicit plot must be function or equation" # At this point self.f is the expression to be equated to zero. self.f = f.lhs() - f.rhs()
def implicit_plot(f, xrange, yrange, **options): r""" ``implicit_plot`` takes a function of two variables, `f(x,y)` and plots the curve `f(x,y) = 0` over the specified ``xrange`` and ``yrange`` as demonstrated below. ``implicit_plot(f, (xmin, xmax), (ymin, ymax), ...)`` ``implicit_plot(f, (x, xmin, xmax), (y, ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables or equation in two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values or ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values or ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 150); number of points to plot in each direction of the grid - ``fill`` -- boolean (default: ``False``); if ``True``, fill the region `f(x,y) < 0`. - ``linewidth`` -- integer (default: None), if a single integer all levels will be of the width given, otherwise the levels will be plotted with the widths in the order given. - ``linestyle`` -- string (default: None), the style of the line to be plotted, one of: ``"solid"``, ``"dashed"``, ``"dashdot"`` or ``"dotted"``, respectively ``"-"``, ``"--"``, ``"-."``, or ``":"``. - ``color`` -- string (default: ``blue``), the color of the plot. Colors are defined in :mod:`sage.plot.colors`; try ``colors?`` to see them all. - ``legend_label`` -- the label for this item in the legend - ``base`` - (default: 10) the base of the logarithm if a logarithmic scale is set. This must be greater than 1. The base can be also given as a list or tuple ``(basex, basey)``. ``basex`` sets the base of the logarithm along the horizontal axis and ``basey`` sets the base along the vertical axis. - ``scale`` -- (default: ``"linear"``) string. The scale of the axes. Possible values are ``"linear"``, ``"loglog"``, ``"semilogx"``, ``"semilogy"``. The scale can be also be given as single argument that is a list or tuple ``(scale, base)`` or ``(scale, basex, basey)``. The ``"loglog"`` scale sets both the horizontal and vertical axes to logarithmic scale. The ``"semilogx"`` scale sets the horizontal axis to logarithmic scale. The ``"semilogy"`` scale sets the vertical axis to logarithmic scale. The ``"linear"`` scale is the default value when :class:`~sage.plot.graphics.Graphics` is initialized. EXAMPLES: A simple circle with a radius of 2. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: var("x y") (x, y) sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3)) Graphics object consisting of 1 graphics primitive I can do the same thing, but using a callable function so I don't need to explicitly define the variables in the ranges, and filling the inside:: sage: f(x,y) = x^2 + y^2 - 2 sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True) Graphics object consisting of 1 graphics primitive The same circle but with a different line width:: sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6) Graphics object consisting of 1 graphics primitive And again the same circle but this time with a dashdot border:: sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot') Graphics object consisting of 1 graphics primitive You can also plot an equation:: sage: var("x y") (x, y) sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3)) Graphics object consisting of 1 graphics primitive You can even change the color of the plot:: sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3), color="red") Graphics object consisting of 1 graphics primitive Here is a beautiful (and long) example which also tests that all colors work with this:: sage: G = Graphics() sage: counter = 0 sage: for col in colors.keys(): # long time ... G += implicit_plot(x^2+y^2==1+counter*.1, (x,-4,4),(y,-4,4),color=col) ... counter += 1 sage: G.show(frame=False) We can define a level-`n` approximation of the boundary of the Mandelbrot set:: sage: def mandel(n): ... c = polygen(CDF, 'c') ... z = 0 ... for i in range(n): ... z = z*z + c ... def f(x, y): ... val = z(CDF(x, y)) ... return val.norm() - 4 ... return f The first-level approximation is just a circle:: sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)) Graphics object consisting of 1 graphics primitive A third-level approximation starts to get interesting:: sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5)) Graphics object consisting of 1 graphics primitive The seventh-level approximation is a degree 64 polynomial, and ``implicit_plot`` does a pretty good job on this part of the curve. (``plot_points=200`` looks even better, but it takes over a second.) :: sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50) Graphics object consisting of 1 graphics primitive When making a filled implicit plot using a python function rather than a symbolic expression the user should increase the number of plot points to avoid artifacts:: sage: implicit_plot(lambda x,y: x^2+y^2-2, (x,-3,3), (y,-3,3), fill=True, plot_points=500) # long time Graphics object consisting of 1 graphics primitive An example of an implicit plot on 'loglog' scale:: sage: implicit_plot(x^2+y^2 == 200, (x,1,200), (y,1,200), scale='loglog') Graphics object consisting of 1 graphics primitive TESTS:: sage: f(x,y) = x^2 + y^2 - 2 sage: implicit_plot(f, (-3, 3), (-3, 3),fill=5) Traceback (most recent call last): ... ValueError: fill=5 is not supported """ from sage.symbolic.expression import is_SymbolicEquation if is_SymbolicEquation(f): if f.operator() != operator.eq: raise ValueError( "input to implicit plot must be function or equation") f = f.lhs() - f.rhs() linewidths = options.pop('linewidth', None) linestyles = options.pop('linestyle', None) if 'color' in options: options['cmap'] = [options.pop('color', None)] if options['fill'] is True: options.pop('fill') options.pop('contours', None) options.pop('cmap', None) from sage.symbolic.expression import is_Expression if not is_Expression(f): return region_plot(lambda x, y: f(x, y) < 0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, **options) else: return region_plot(f < 0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, **options) elif options['fill'] is False: return contour_plot(f, xrange, yrange, linewidths=linewidths, linestyles=linestyles, **options) else: raise ValueError("fill=%s is not supported" % options['fill'])
def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, **kwds): """ Return a ``UniqueFactory`` key and possibly extra parameters. INPUT: See the documentation for :class:`EllipticCurveFactory`. OUTPUT: A pair ``(key, extra_args)``: - ``key`` has the form `(R, (a_1, a_2, a_3, a_4, a_6))`, representing a ring and the Weierstrass coefficients of an elliptic curve over that ring; - ``extra_args`` is a dictionary containing additional data to be inserted into the elliptic curve structure. EXAMPLES:: sage: EllipticCurve.create_key_and_extra_args(j=8000) ((Rational Field, (0, -1, 0, -3, -1)), {}) When constructing a curve over `\\QQ` from a Cremona or LMFDB label, the invariants from the database are returned as ``extra_args``:: sage: key, data = EllipticCurve.create_key_and_extra_args('389.a1') sage: key (Rational Field, (0, 1, 1, -2, 0)) sage: data['conductor'] 389 sage: data['cremona_label'] '389a1' sage: data['lmfdb_label'] '389.a1' sage: data['rank'] 2 sage: data['torsion_order'] 1 User-specified keywords are also included in ``extra_args``:: sage: key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4) sage: data['rank'] 4 Furthermore, keywords takes precedence over data from the database, which can be used to specify an alternative set of generators for the Mordell-Weil group:: sage: key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]]) sage: data['gens'] [[1, -1], [-2, 3], [4, -7]] sage: E = EllipticCurve.create_object(0, key, **data) sage: E.gens() [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)] Note that elliptic curves are equal if and only they have the same base ring and Weierstrass equation; the data in ``extra_args`` do not influence comparison of elliptic curves. A consequence of this is that passing keyword arguments only works when constructing an elliptic curve the first time:: sage: E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] sage: E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] .. WARNING:: Manually specifying extra data is almost never necessary and is not guaranteed to have any effect, as the above example shows. Almost no checking is done, so specifying incorrect data may lead to wrong results of computations instead of errors or warnings. """ R = None if is_Ring(x): (R, x) = (x, y) if j is not None: if R is not None: try: j = R(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError( "First parameter must be a ring containing %s" % j) elif x is not None: raise ValueError( "First parameter (if present) must be a ring when j is specified" ) x = coefficients_from_j(j, minimal_twist) if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if is_MPolynomial(x): if y is None: x = coefficients_from_Weierstrass_polynomial(x) else: x = coefficients_from_cubic(x, y, morphism=False) if isinstance(x, string_types): # Interpret x as a Cremona or LMFDB label. from sage.databases.cremona import CremonaDatabase x, data = CremonaDatabase().coefficients_and_data(x) # User-provided keywords may override database entries. data.update(kwds) kwds = data if not isinstance(x, (list, tuple)): raise TypeError("invalid input to EllipticCurve constructor") if len(x) == 2: x = (0, 0, 0, x[0], x[1]) elif len(x) != 5: raise ValueError( "sequence of coefficients must have length 2 or 5") if R is None: R = Sequence(x).universe() if R in (rings.ZZ, ) + integer_types: R = rings.QQ return (R, tuple(R(a) for a in x)), kwds
def EllipticCurve(x=None, y=None, j=None, minimal_twist=True): r""" There are several ways to construct an elliptic curve: .. math:: y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6. - EllipticCurve([a1,a2,a3,a4,a6]): Elliptic curve with given a-invariants. The invariants are coerced into the parent of the first element. If all are integers, they are coerced into the rational numbers. - EllipticCurve([a4,a6]): Same as above, but a1=a2=a3=0. - EllipticCurve(label): Returns the elliptic curve over Q from the Cremona database with the given label. The label is a string, such as "11a" or "37b2". The letters in the label *must* be lower case (Cremona's new labeling). - EllipticCurve(R, [a1,a2,a3,a4,a6]): Create the elliptic curve over R with given a-invariants. Here R can be an arbitrary ring. Note that addition need not be defined. - EllipticCurve(j=j0) or EllipticCurve_from_j(j0): Return an elliptic curve with j-invariant `j0`. In each case above where the input is a list of length 2 or 5, one can instead give a 2 or 5-tuple instead. EXAMPLES: We illustrate creating elliptic curves. :: sage: EllipticCurve([0,0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field We create a curve from a Cremona label:: sage: EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field sage: EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field sage: EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Old Cremona labels are allowed:: sage: EllipticCurve('2400FF') Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field Unicode labels are allowed:: sage: EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field We create curves over a finite field as follows:: sage: EllipticCurve([GF(5)(0),0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 sage: EllipticCurve(GF(5), [0, 0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type "elliptic curve over a finite field":: sage: F = Zmod(101) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 101 In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite are of type "generic elliptic curve":: sage: F = Zmod(95) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 95 The following is a curve over the complex numbers:: sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297 We can also create elliptic curves by giving the Weierstrass equation:: sage: x, y = var('x,y') sage: EllipticCurve(y^2 + y == x^3 + x - 9) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field sage: R.<x,y> = GF(5)[] sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5 We can explicitly specify the `j`-invariant:: sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2 See trac #6657:: sage: EllipticCurve(GF(144169),j=1728) Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169 By default, when a rational value of `j` is given, the constructed curve is a minimal twist (minimal conductor for curves with that `j`-invariant). This can be changed by setting the optional parameter ``minimal_twist``, which is True by default, to False:: sage: EllipticCurve(j=100) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E =EllipticCurve(j=100); E Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E.conductor() 33129800 sage: E.j_invariant() 100 sage: E =EllipticCurve(j=100, minimal_twist=False); E Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field sage: E.conductor() 298168200 sage: E.j_invariant() 100 Without this option, constructing the curve could take a long time since both `j` and `j-1728` have to be factored to compute the minimal twist (see :trac:`13100`):: sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False) sage: E.j_invariant() == 2^256+1 True TESTS:: sage: R = ZZ['u', 'v'] sage: EllipticCurve(R, [1,1]) Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v over Integer Ring We create a curve and a point over QQbar (see #6879):: sage: E = EllipticCurve(QQbar,[0,1]) sage: E(0) (0 : 1 : 0) sage: E.base_field() Algebraic Field sage: E = EllipticCurve(RR,[1,2]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: EllipticCurve(CC,[3,4]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field Algebraic Field See trac #6657:: sage: EllipticCurve(3,j=1728) Traceback (most recent call last): ... ValueError: First parameter (if present) must be a ring when j is specified sage: EllipticCurve(GF(5),j=3/5) Traceback (most recent call last): ... ValueError: First parameter must be a ring containing 3/5 If the universe of the coefficients is a general field, the object constructed has type EllipticCurve_field. Otherwise it is EllipticCurve_generic. See trac #9816:: sage: E = EllipticCurve([QQbar(1),3]); E Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([RR(1),3]); E Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([i,i]); E Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Symbolic Ring sage: SR in Fields() True sage: F = FractionField(PolynomialRing(QQ,'t')) sage: t = F.gen() sage: E = EllipticCurve([t,0]); E Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field See :trac:`12517`:: sage: E = EllipticCurve([1..5]) sage: EllipticCurve(E.a_invariants()) Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field See :trac:`11773`:: sage: E = EllipticCurve() Traceback (most recent call last): ... TypeError: invalid input to EllipticCurve constructor """ import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field # here to avoid circular includes if j is not None: if not x is None: if rings.is_Ring(x): try: j = x(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError, "First parameter must be a ring containing %s"%j else: raise ValueError, "First parameter (if present) must be a ring when j is specified" return EllipticCurve_from_j(j, minimal_twist) if x is None: raise TypeError, "invalid input to EllipticCurve constructor" if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if rings.is_MPolynomial(x) and y is None: f = x if f.degree() != 3: raise ValueError, "Elliptic curves must be defined by a cubic polynomial." if f.degrees() == (3,2): x, y = f.parent().gens() elif f.degree() == (2,3): y, x = f.parent().gens() elif len(f.parent().gens()) == 2 or len(f.parent().gens()) == 3 and f.is_homogeneous(): # We'd need a point too... raise NotImplementedError, "Construction of an elliptic curve from a generic cubic not yet implemented." else: raise ValueError, "Defining polynomial must be a cubic polynomial in two variables." try: if f.coefficient(x**3) < 0: f = -f # is there a nicer way to extract the coefficients? a1 = a2 = a3 = a4 = a6 = 0 for coeff, mon in f: if mon == x**3: assert coeff == 1 elif mon == x**2: a2 = coeff elif mon == x: a4 = coeff elif mon == 1: a6 = coeff elif mon == y**2: assert coeff == -1 elif mon == x*y: a1 = -coeff elif mon == y: a3 = -coeff else: assert False return EllipticCurve([a1, a2, a3, a4, a6]) except AssertionError: raise NotImplementedError, "Construction of an elliptic curve from a generic cubic not yet implemented." if rings.is_Ring(x): if rings.is_RationalField(x): return ell_rational_field.EllipticCurve_rational_field(x, y) elif rings.is_FiniteField(x) or (rings.is_IntegerModRing(x) and x.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_pAdicField(x): return ell_padic_field.EllipticCurve_padic_field(x, y) elif rings.is_NumberField(x): return ell_number_field.EllipticCurve_number_field(x, y) elif x in _Fields: return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y) if isinstance(x, unicode): x = str(x) if isinstance(x, str): return ell_rational_field.EllipticCurve_rational_field(x) if rings.is_RingElement(x) and y is None: raise TypeError, "invalid input to EllipticCurve constructor" if not isinstance(x, (list, tuple)): raise TypeError, "invalid input to EllipticCurve constructor" x = Sequence(x) if not (len(x) in [2,5]): raise ValueError, "sequence of coefficients must have length 2 or 5" R = x.universe() if isinstance(x[0], (rings.Rational, rings.Integer, int, long)): return ell_rational_field.EllipticCurve_rational_field(x, y) elif rings.is_NumberField(R): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_pAdicField(R): return ell_padic_field.EllipticCurve_padic_field(x, y) elif rings.is_FiniteField(R) or (rings.is_IntegerModRing(R) and R.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif R in _Fields: return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y)
def implicit_plot(f, xrange, yrange, **options): r""" ``implicit_plot`` takes a function of two variables, `f(x,y)` and plots the curve `f(x,y) = 0` over the specified ``xrange`` and ``yrange`` as demonstrated below. ``implicit_plot(f, (xmin, xmax), (ymin, ymax), ...)`` ``implicit_plot(f, (x, xmin, xmax), (y, ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables or equation in two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values or ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values or ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 150); number of points to plot in each direction of the grid - ``fill`` -- boolean (default: ``False``); if ``True``, fill the region `f(x,y) < 0`. - ``linewidth`` -- integer (default: None), if a single integer all levels will be of the width given, otherwise the levels will be plotted with the widths in the order given. - ``linestyle`` -- string (default: None), the style of the line to be plotted, one of: solid, dashed, dashdot or dotted. - ``color`` -- string (default: ``blue``), the color of the plot. Colors are defined in :mod:`sage.plot.colors`; try ``colors?`` to see them all. - ``legend_label`` -- the label for this item in the legend EXAMPLES: A simple circle with a radius of 2. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: var("x y") (x, y) sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3)) I can do the same thing, but using a callable function so I don't need to explicitly define the variables in the ranges, and filling the inside:: sage: f(x,y) = x^2 + y^2 - 2 sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True) The same circle but with a different line width:: sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6) And again the same circle but this time with a dashdot border:: sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot') You can also plot an equation:: sage: var("x y") (x, y) sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3)) You can even change the color of the plot:: sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3), color="red") Here is a beautiful (and long) example which also tests that all colors work with this:: sage: G = Graphics() sage: counter = 0 sage: for col in colors.keys(): # long time ... G += implicit_plot(x^2+y^2==1+counter*.1, (x,-4,4),(y,-4,4),color=col) ... counter += 1 sage: G.show(frame=False) We can define a level-`n` approximation of the boundary of the Mandelbrot set:: sage: def mandel(n): ... c = polygen(CDF, 'c') ... z = 0 ... for i in range(n): ... z = z*z + c ... def f(x, y): ... val = z(CDF(x, y)) ... return val.norm() - 4 ... return f The first-level approximation is just a circle:: sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)) A third-level approximation starts to get interesting:: sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5)) The seventh-level approximation is a degree 64 polynomial, and ``implicit_plot`` does a pretty good job on this part of the curve. (``plot_points=200`` looks even better, but it takes over a second.) :: sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50) When making a filled implicit plot using a python function rather than a symbolic expression the user should increase the number of plot points to avoid artifacts:: sage: implicit_plot(lambda x,y: x^2+y^2-2, (x,-3,3), (y,-3,3), fill=True, plot_points=500) # long time TESTS:: sage: f(x,y) = x^2 + y^2 - 2 sage: implicit_plot(f, (-3, 3), (-3, 3),fill=5) Traceback (most recent call last): ... ValueError: fill=5 is not supported """ from sage.symbolic.expression import is_SymbolicEquation if is_SymbolicEquation(f): if f.operator() != operator.eq: raise ValueError, "input to implicit plot must be function or equation" f = f.lhs() - f.rhs() linewidths = options.pop('linewidth', None) linestyles = options.pop('linestyle', None) if 'color' in options: options['cmap']=[options.pop('color', None)] if options['fill'] is True: options.pop('fill') options.pop('contours',None) options.pop('cmap',None) from sage.symbolic.expression import is_Expression if not is_Expression(f): return region_plot(lambda x,y: f(x,y)<0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, **options) else: return region_plot(f<0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, **options) elif options['fill'] is False: return contour_plot(f, xrange, yrange, linewidths=linewidths, linestyles=linestyles, **options) else: raise ValueError("fill=%s is not supported" % options['fill'])
def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, **kwds): """ Return a ``UniqueFactory`` key and possibly extra parameters. INPUT: See the documentation for :class:`EllipticCurveFactory`. OUTPUT: A pair ``(key, extra_args)``: - ``key`` has the form `(R, (a_1, a_2, a_3, a_4, a_6))`, representing a ring and the Weierstrass coefficients of an elliptic curve over that ring; - ``extra_args`` is a dictionary containing additional data to be inserted into the elliptic curve structure. EXAMPLES:: sage: EllipticCurve.create_key_and_extra_args(j=8000) ((Rational Field, (0, -1, 0, -3, -1)), {}) When constructing a curve over `\\QQ` from a Cremona or LMFDB label, the invariants from the database are returned as ``extra_args``:: sage: key, data = EllipticCurve.create_key_and_extra_args('389.a1') sage: key (Rational Field, (0, 1, 1, -2, 0)) sage: data['conductor'] 389 sage: data['cremona_label'] '389a1' sage: data['lmfdb_label'] '389.a1' sage: data['rank'] 2 sage: data['torsion_order'] 1 User-specified keywords are also included in ``extra_args``:: sage: key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4) sage: data['rank'] 4 Furthermore, keywords takes precedence over data from the database, which can be used to specify an alternative set of generators for the Mordell-Weil group:: sage: key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]]) sage: data['gens'] [[1, -1], [-2, 3], [4, -7]] sage: E = EllipticCurve.create_object(0, key, **data) sage: E.gens() [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)] Note that elliptic curves are equal if and only they have the same base ring and Weierstrass equation; the data in ``extra_args`` do not influence comparison of elliptic curves. A consequence of this is that passing keyword arguments only works when constructing an elliptic curve the first time: sage: E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] sage: E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]]) sage: E.gens() [(-1 : 1 : 1), (3 : 4 : 1)] .. WARNING:: Manually specifying extra data is almost never necessary and is not guaranteed to have any effect, as the above example shows. Almost no checking is done, so specifying incorrect data may lead to wrong results of computations instead of errors or warnings. """ R = None if is_Ring(x): (R, x) = (x, y) if j is not None: if R is not None: try: j = R(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError("First parameter must be a ring containing %s" % j) elif x is not None: raise ValueError("First parameter (if present) must be a ring when j is specified") x = coefficients_from_j(j, minimal_twist) if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if is_MPolynomial(x): if y is None: x = coefficients_from_Weierstrass_polynomial(x) else: x = coefficients_from_cubic(x, y, morphism=False) if isinstance(x, basestring): # Interpret x as a Cremona or LMFDB label. from sage.databases.cremona import CremonaDatabase x, data = CremonaDatabase().coefficients_and_data(x) # User-provided keywords may override database entries. data.update(kwds) kwds = data if not isinstance(x, (list, tuple)): raise TypeError("invalid input to EllipticCurve constructor") if len(x) == 2: x = (0, 0, 0, x[0], x[1]) elif len(x) != 5: raise ValueError("sequence of coefficients must have length 2 or 5") if R is None: R = Sequence(x).universe() if R in (rings.ZZ, int, long): R = rings.QQ return (R, tuple(R(a) for a in x)), kwds
def EllipticCurve(x=None, y=None, j=None, minimal_twist=True): r""" Construct an elliptic curve. In Sage, an elliptic curve is always specified by its a-invariants .. math:: y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6. INPUT: There are several ways to construct an elliptic curve: - ``EllipticCurve([a1,a2,a3,a4,a6])``: Elliptic curve with given a-invariants. The invariants are coerced into the parent of the first element. If all are integers, they are coerced into the rational numbers. - ``EllipticCurve([a4,a6])``: Same as above, but `a_1=a_2=a_3=0`. - ``EllipticCurve(label)``: Returns the elliptic curve over Q from the Cremona database with the given label. The label is a string, such as ``"11a"`` or ``"37b2"``. The letters in the label *must* be lower case (Cremona's new labeling). - ``EllipticCurve(R, [a1,a2,a3,a4,a6])``: Create the elliptic curve over ``R`` with given a-invariants. Here ``R`` can be an arbitrary ring. Note that addition need not be defined. - ``EllipticCurve(j=j0)`` or ``EllipticCurve_from_j(j0)``: Return an elliptic curve with j-invariant ``j0``. - ``EllipticCurve(polynomial)``: Read off the a-invariants from the polynomial coefficients, see :func:`EllipticCurve_from_Weierstrass_polynomial`. In each case above where the input is a list of length 2 or 5, one can instead give a 2 or 5-tuple instead. EXAMPLES: We illustrate creating elliptic curves:: sage: EllipticCurve([0,0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field We create a curve from a Cremona label:: sage: EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field sage: EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field sage: EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Old Cremona labels are allowed:: sage: EllipticCurve('2400FF') Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field Unicode labels are allowed:: sage: EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field We create curves over a finite field as follows:: sage: EllipticCurve([GF(5)(0),0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 sage: EllipticCurve(GF(5), [0, 0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type "elliptic curve over a finite field":: sage: F = Zmod(101) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 101 In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite are of type "generic elliptic curve":: sage: F = Zmod(95) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 95 The following is a curve over the complex numbers:: sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297 We can also create elliptic curves by giving the Weierstrass equation:: sage: x, y = var('x,y') sage: EllipticCurve(y^2 + y == x^3 + x - 9) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field sage: R.<x,y> = GF(5)[] sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5 We can explicitly specify the `j`-invariant:: sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2 See :trac:`6657` :: sage: EllipticCurve(GF(144169),j=1728) Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169 By default, when a rational value of `j` is given, the constructed curve is a minimal twist (minimal conductor for curves with that `j`-invariant). This can be changed by setting the optional parameter ``minimal_twist``, which is True by default, to False:: sage: EllipticCurve(j=100) Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E =EllipticCurve(j=100); E Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field sage: E.conductor() 33129800 sage: E.j_invariant() 100 sage: E =EllipticCurve(j=100, minimal_twist=False); E Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field sage: E.conductor() 298168200 sage: E.j_invariant() 100 Without this option, constructing the curve could take a long time since both `j` and `j-1728` have to be factored to compute the minimal twist (see :trac:`13100`):: sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False) sage: E.j_invariant() == 2^256+1 True TESTS:: sage: R = ZZ['u', 'v'] sage: EllipticCurve(R, [1,1]) Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v over Integer Ring We create a curve and a point over QQbar (see #6879):: sage: E = EllipticCurve(QQbar,[0,1]) sage: E(0) (0 : 1 : 0) sage: E.base_field() Algebraic Field sage: E = EllipticCurve(RR,[1,2]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: EllipticCurve(CC,[3,4]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field Algebraic Field See :trac:`6657` :: sage: EllipticCurve(3,j=1728) Traceback (most recent call last): ... ValueError: First parameter (if present) must be a ring when j is specified sage: EllipticCurve(GF(5),j=3/5) Traceback (most recent call last): ... ValueError: First parameter must be a ring containing 3/5 If the universe of the coefficients is a general field, the object constructed has type EllipticCurve_field. Otherwise it is EllipticCurve_generic. See :trac:`9816` :: sage: E = EllipticCurve([QQbar(1),3]); E Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([RR(1),3]); E Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([i,i]); E Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Symbolic Ring sage: SR in Fields() True sage: F = FractionField(PolynomialRing(QQ,'t')) sage: t = F.gen() sage: E = EllipticCurve([t,0]); E Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field See :trac:`12517`:: sage: E = EllipticCurve([1..5]) sage: EllipticCurve(E.a_invariants()) Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field See :trac:`11773`:: sage: E = EllipticCurve() Traceback (most recent call last): ... TypeError: invalid input to EllipticCurve constructor """ import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field # here to avoid circular includes if j is not None: if not x is None: if is_Ring(x): try: j = x(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError, "First parameter must be a ring containing %s" % j else: raise ValueError, "First parameter (if present) must be a ring when j is specified" return EllipticCurve_from_j(j, minimal_twist) if x is None: raise TypeError, "invalid input to EllipticCurve constructor" if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if is_MPolynomial(x): if y is None: return EllipticCurve_from_Weierstrass_polynomial(x) else: return EllipticCurve_from_cubic(x, y, morphism=False) if is_Ring(x): if is_RationalField(x): return ell_rational_field.EllipticCurve_rational_field(x, y) elif is_FiniteField(x) or (is_IntegerModRing(x) and x.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_pAdicField(x): return ell_padic_field.EllipticCurve_padic_field(x, y) elif is_NumberField(x): return ell_number_field.EllipticCurve_number_field(x, y) elif x in _Fields: return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y) if isinstance(x, unicode): x = str(x) if isinstance(x, basestring): return ell_rational_field.EllipticCurve_rational_field(x) if is_RingElement(x) and y is None: raise TypeError, "invalid input to EllipticCurve constructor" if not isinstance(x, (list, tuple)): raise TypeError, "invalid input to EllipticCurve constructor" x = Sequence(x) if not (len(x) in [2, 5]): raise ValueError, "sequence of coefficients must have length 2 or 5" R = x.universe() if isinstance(x[0], (rings.Rational, rings.Integer, int, long)): return ell_rational_field.EllipticCurve_rational_field(x, y) elif is_NumberField(R): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_pAdicField(R): return ell_padic_field.EllipticCurve_padic_field(x, y) elif is_FiniteField(R) or (is_IntegerModRing(R) and R.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif R in _Fields: return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y)
def EllipticCurve(x=None, y=None, j=None): r""" There are several ways to construct an elliptic curve: .. math:: y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6. - EllipticCurve([a1,a2,a3,a4,a6]): Elliptic curve with given a-invariants. The invariants are coerced into the parent of the first element. If all are integers, they are coerced into the rational numbers. - EllipticCurve([a4,a6]): Same as above, but a1=a2=a3=0. - EllipticCurve(label): Returns the elliptic curve over Q from the Cremona database with the given label. The label is a string, such as "11a" or "37b2". The letters in the label *must* be lower case (Cremona's new labeling). - EllipticCurve(R, [a1,a2,a3,a4,a6]): Create the elliptic curve over R with given a-invariants. Here R can be an arbitrary ring. Note that addition need not be defined. - EllipticCurve(j): Return an elliptic curve with j-invariant `j`. Warning: this is deprecated. Use ``EllipticCurve_from_j(j)`` or ``EllipticCurve(j=j)`` instead. In each case above where the input is a list of length 2 or 5, one can instead give a 2 or 5-tuple instead. EXAMPLES: We illustrate creating elliptic curves. :: sage: EllipticCurve([0,0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field We create a curve from a Cremona label:: sage: EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field sage: EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field sage: EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Unicode labels are allowed:: sage: EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field We create curves over a finite field as follows:: sage: EllipticCurve([GF(5)(0),0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 sage: EllipticCurve(GF(5), [0, 0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type "elliptic curve over a finite field":: sage: F = Zmod(101) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 101 In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite are of type "generic elliptic curve":: sage: F = Zmod(95) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'> sage: E.category() Category of schemes over Ring of integers modulo 95 The following is a curve over the complex numbers:: sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297 We can also create elliptic curves by giving the Weierstrass equation:: sage: x, y = var('x,y') sage: EllipticCurve(y^2 + y == x^3 + x - 9) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field sage: R.<x,y> = GF(5)[] sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5 We can explicitly specify the `j`-invariant:: sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2 See trac #6657:: sage: EllipticCurve(GF(144169),j=1728) Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169 TESTS:: sage: R = ZZ['u', 'v'] sage: EllipticCurve(R, [1,1]) Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v over Integer Ring We create a curve and a point over QQbar (see #6879):: sage: E = EllipticCurve(QQbar,[0,1]) sage: E(0) (0 : 1 : 0) sage: E.base_field() Algebraic Field sage: E = EllipticCurve(RR,[1,2]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: EllipticCurve(CC,[3,4]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field Algebraic Field See trac #6657:: sage: EllipticCurve(3,j=1728) Traceback (most recent call last): ... ValueError: First parameter (if present) must be a ring when j is specified sage: EllipticCurve(GF(5),j=3/5) Traceback (most recent call last): ... ValueError: First parameter must be a ring containing 3/5 If the universe of the coefficients is a general field, the object constructed has type EllipticCurve_field. Otherwise it is EllipticCurve_generic. See trac #9816:: sage: E = EllipticCurve([QQbar(1),3]); E Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([RR(1),3]); E Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E = EllipticCurve([i,i]); E Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Symbolic Ring sage: is_field(SR) True sage: F = FractionField(PolynomialRing(QQ,'t')) sage: t = F.gen() sage: E = EllipticCurve([t,0]); E Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'> sage: E.category() Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field See :trac:`12517`:: sage: E = EllipticCurve([1..5]) sage: EllipticCurve(E.a_invariants()) Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field """ import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field # here to avoid circular includes if j is not None: if not x is None: if rings.is_Ring(x): try: j = x(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError, "First parameter must be a ring containing %s"%j else: raise ValueError, "First parameter (if present) must be a ring when j is specified" return EllipticCurve_from_j(j) assert x is not None if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if rings.is_MPolynomial(x) and y is None: f = x if f.degree() != 3: raise ValueError, "Elliptic curves must be defined by a cubic polynomial." if f.degrees() == (3,2): x, y = f.parent().gens() elif f.degree() == (2,3): y, x = f.parent().gens() elif len(f.parent().gens()) == 2 or len(f.parent().gens()) == 3 and f.is_homogeneous(): # We'd need a point too... raise NotImplementedError, "Construction of an elliptic curve from a generic cubic not yet implemented." else: raise ValueError, "Defining polynomial must be a cubic polynomial in two variables." try: if f.coefficient(x**3) < 0: f = -f # is there a nicer way to extract the coefficients? a1 = a2 = a3 = a4 = a6 = 0 for coeff, mon in f: if mon == x**3: assert coeff == 1 elif mon == x**2: a2 = coeff elif mon == x: a4 = coeff elif mon == 1: a6 = coeff elif mon == y**2: assert coeff == -1 elif mon == x*y: a1 = -coeff elif mon == y: a3 = -coeff else: assert False return EllipticCurve([a1, a2, a3, a4, a6]) except AssertionError: raise NotImplementedError, "Construction of an elliptic curve from a generic cubic not yet implemented." if rings.is_Ring(x): if rings.is_RationalField(x): return ell_rational_field.EllipticCurve_rational_field(x, y) elif rings.is_FiniteField(x) or (rings.is_IntegerModRing(x) and x.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_pAdicField(x): return ell_padic_field.EllipticCurve_padic_field(x, y) elif rings.is_NumberField(x): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_Field(x): return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y) if isinstance(x, unicode): x = str(x) if isinstance(x, str): return ell_rational_field.EllipticCurve_rational_field(x) if rings.is_RingElement(x) and y is None: from sage.misc.misc import deprecation deprecation("'EllipticCurve(j)' is deprecated; use 'EllipticCurve_from_j(j)' or 'EllipticCurve(j=j)' instead.") # Fixed for all characteristics and cases by John Cremona j=x F=j.parent().fraction_field() char=F.characteristic() if char==2: if j==0: return EllipticCurve(F, [ 0, 0, 1, 0, 0 ]) else: return EllipticCurve(F, [ 1, 0, 0, 0, 1/j ]) if char==3: if j==0: return EllipticCurve(F, [ 0, 0, 0, 1, 0 ]) else: return EllipticCurve(F, [ 0, j, 0, 0, -j**2 ]) if j == 0: return EllipticCurve(F, [ 0, 0, 0, 0, 1 ]) if j == 1728: return EllipticCurve(F, [ 0, 0, 0, 1, 0 ]) k=j-1728 return EllipticCurve(F, [0,0,0,-3*j*k, -2*j*k**2]) if not isinstance(x, (list, tuple)): raise TypeError, "invalid input to EllipticCurve constructor" x = Sequence(x) if not (len(x) in [2,5]): raise ValueError, "sequence of coefficients must have length 2 or 5" R = x.universe() if isinstance(x[0], (rings.Rational, rings.Integer, int, long)): return ell_rational_field.EllipticCurve_rational_field(x, y) elif rings.is_NumberField(R): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_pAdicField(R): return ell_padic_field.EllipticCurve_padic_field(x, y) elif rings.is_FiniteField(R) or (rings.is_IntegerModRing(R) and R.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_Field(R): return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y)
def implicit_plot(f, xrange, yrange, **options): r""" ``implicit_plot`` takes a function of two variables, `f(x,y)` and plots the curve `f(x,y) = 0` over the specified ``xrange`` and ``yrange`` as demonstrated below. ``implicit_plot(f, (xmin, xmax), (ymin, ymax), ...)`` ``implicit_plot(f, (x, xmin, xmax), (y, ymin, ymax), ...)`` INPUT: - ``f`` -- a function of two variables or equation in two variables - ``(xmin, xmax)`` -- 2-tuple, the range of ``x`` values or ``(x,xmin,xmax)`` - ``(ymin, ymax)`` -- 2-tuple, the range of ``y`` values or ``(y,ymin,ymax)`` The following inputs must all be passed in as named parameters: - ``plot_points`` -- integer (default: 150); number of points to plot in each direction of the grid - ``fill`` -- boolean (default: ``False``); if ``True``, fill the region `f(x,y) < 0`. - ``linewidth`` -- integer (default: None), if a single integer all levels will be of the width given, otherwise the levels will be plotted with the widths in the order given. - ``linestyle`` -- string (default: None), the style of the line to be plotted, one of: solid, dashed, dashdot or dotted. - ``color`` -- string (default: ``blue``), the color of the plot. Colors are defined in :mod:`sage.plot.colors`; try ``colors?`` to see them all. - ``legend_label`` -- the label for this item in the legend EXAMPLES: A simple circle with a radius of 2. Note that since the input function is an expression, we need to explicitly declare the variables in 3-tuples for the range:: sage: var("x y") (x, y) sage: implicit_plot(x^2+y^2-2, (x,-3,3), (y,-3,3)) I can do the same thing, but using a callable function so I don't need to explicitly define the variables in the ranges, and filling the inside:: sage: x,y = var('x,y') sage: f(x,y) = x^2 + y^2 - 2 sage: implicit_plot(f, (-3, 3), (-3, 3),fill=True) The same circle but with a different line width:: sage: implicit_plot(f, (-3,3), (-3,3), linewidth=6) And again the same circle but this time with a dashdot border:: sage: implicit_plot(f, (-3,3), (-3,3), linestyle='dashdot') You can also plot an equation:: sage: var("x y") (x, y) sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3)) You can even change the color of the plot:: sage: implicit_plot(x^2+y^2 == 2, (x,-3,3), (y,-3,3), color="red") Here is a beautiful (and long) example which also tests that all colors work with this:: sage: G = Graphics() sage: counter = 0 sage: for col in colors.keys(): # long time ... G += implicit_plot(x^2+y^2==1+counter*.1, (x,-4,4),(y,-4,4),color=col) ... counter += 1 sage: G.show(frame=False) We can define a level-`n` approximation of the boundary of the Mandelbrot set:: sage: def mandel(n): ... c = polygen(CDF, 'c') ... z = 0 ... for i in range(n): ... z = z*z + c ... def f(x, y): ... val = z(CDF(x, y)) ... return val.norm() - 4 ... return f The first-level approximation is just a circle:: sage: implicit_plot(mandel(1), (-3, 3), (-3, 3)) A third-level approximation starts to get interesting:: sage: implicit_plot(mandel(3), (-2, 1), (-1.5, 1.5)) The seventh-level approximation is a degree 64 polynomial, and ``implicit_plot`` does a pretty good job on this part of the curve. (``plot_points=200`` looks even better, but it takes over a second.) :: sage: implicit_plot(mandel(7), (-0.3, 0.05), (-1.15, -0.9),plot_points=50) """ from sage.symbolic.expression import is_SymbolicEquation if is_SymbolicEquation(f): if f.operator() != operator.eq: raise ValueError, "input to implicit plot must be function or equation" f = f.lhs() - f.rhs() linewidths = options.pop('linewidth', None) linestyles = options.pop('linestyle', None) if 'color' in options: options['cmap']=[options.pop('color', None)] return contour_plot(f, xrange, yrange, linewidths=linewidths, linestyles=linestyles, **options)
def EllipticCurve(x=None, y=None, j=None): r""" There are several ways to construct an elliptic curve: .. math:: y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6. - EllipticCurve([a1,a2,a3,a4,a6]): Elliptic curve with given a-invariants. The invariants are coerced into the parent of the first element. If all are integers, they are coerced into the rational numbers. - EllipticCurve([a4,a6]): Same as above, but a1=a2=a3=0. - EllipticCurve(label): Returns the elliptic curve over Q from the Cremona database with the given label. The label is a string, such as "11a" or "37b2". The letters in the label *must* be lower case (Cremona's new labeling). - EllipticCurve(R, [a1,a2,a3,a4,a6]): Create the elliptic curve over R with given a-invariants. Here R can be an arbitrary ring. Note that addition need not be defined. - EllipticCurve(j): Return an elliptic curve with j-invariant `j`. Warning: this is deprecated. Use ``EllipticCurve_from_j(j)`` or ``EllipticCurve(j=j)`` instead. EXAMPLES: We illustrate creating elliptic curves. :: sage: EllipticCurve([0,0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field We create a curve from a Cremona label:: sage: EllipticCurve('37b2') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field sage: EllipticCurve('5077a') Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field sage: EllipticCurve('389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Unicode labels are allowed:: sage: EllipticCurve(u'389a') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field We create curves over a finite field as follows:: sage: EllipticCurve([GF(5)(0),0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 sage: EllipticCurve(GF(5), [0, 0,1,-1,0]) Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5 Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type "elliptic curve over a finite field":: sage: F = Zmod(101) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field'> In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite are of type "generic elliptic curve":: sage: F = Zmod(95) sage: EllipticCurve(F, [2, 3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95 sage: E = EllipticCurve([F(2), F(3)]) sage: type(E) <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic'> The following is a curve over the complex numbers:: sage: E = EllipticCurve(CC, [0,0,1,-1,0]) sage: E Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision sage: E.j_invariant() 2988.97297297297 We can also create elliptic curves by giving the Weierstrass equation:: sage: x, y = var('x,y') sage: EllipticCurve(y^2 + y == x^3 + x - 9) Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field sage: R.<x,y> = GF(5)[] sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x) Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5 We can explicitly specify the `j`-invariant:: sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label() Elliptic Curve defined by y^2 = x^3 - x over Rational Field 1728 '32a2' sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant() Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 2 See trac #6657:: sage: EllipticCurve(GF(144169),j=1728) Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169 TESTS:: sage: R = ZZ['u', 'v'] sage: EllipticCurve(R, [1,1]) Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v over Integer Ring We create a curve and a point over QQbar (see #6879):: sage: E = EllipticCurve(QQbar,[0,1]) sage: E(0) (0 : 1 : 0) sage: E.base_field() Algebraic Field sage: E = EllipticCurve(RR,[1,2]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: EllipticCurve(CC,[3,4]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision Real Field with 53 bits of precision sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field() Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field Algebraic Field See trac #6657:: sage: EllipticCurve(3,j=1728) Traceback (most recent call last): ... ValueError: First parameter (if present) must be a ring when j is specified sage: EllipticCurve(GF(5),j=3/5) Traceback (most recent call last): ... ValueError: First parameter must be a ring containing 3/5 If the universe of the coefficients is a general field, the object constructed has type EllipticCurve_field. Otherwise it is EllipticCurve_generic. See trac #9816:: sage: E = EllipticCurve([QQbar(1),3]); E Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field'> sage: E = EllipticCurve([RR(1),3]); E Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field'> sage: E = EllipticCurve([i,i]); E Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field'> sage: is_field(SR) True sage: F = FractionField(PolynomialRing(QQ,'t')) sage: t = F.gen() sage: E = EllipticCurve([t,0]); E Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: type(E) <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field'> """ import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field # here to avoid circular includes if j is not None: if not x is None: if rings.is_Ring(x): try: j = x(j) except (ZeroDivisionError, ValueError, TypeError): raise ValueError, "First parameter must be a ring containing %s"%j else: raise ValueError, "First parameter (if present) must be a ring when j is specified" return EllipticCurve_from_j(j) assert x is not None if is_SymbolicEquation(x): x = x.lhs() - x.rhs() if parent(x) is SR: x = x._polynomial_(rings.QQ['x', 'y']) if rings.is_MPolynomial(x) and y is None: f = x if f.degree() != 3: raise ValueError, "Elliptic curves must be defined by a cubic polynomial." if f.degrees() == (3,2): x, y = f.parent().gens() elif f.degree() == (2,3): y, x = f.parent().gens() elif len(f.parent().gens()) == 2 or len(f.parent().gens()) == 3 and f.is_homogeneous(): # We'd need a point too... raise NotImplementedError, "Construction of an elliptic curve from a generic cubic not yet implemented." else: raise ValueError, "Defining polynomial must be a cubic polynomial in two variables." try: if f.coefficient(x**3) < 0: f = -f # is there a nicer way to extract the coefficients? a1 = a2 = a3 = a4 = a6 = 0 for coeff, mon in f: if mon == x**3: assert coeff == 1 elif mon == x**2: a2 = coeff elif mon == x: a4 = coeff elif mon == 1: a6 = coeff elif mon == y**2: assert coeff == -1 elif mon == x*y: a1 = -coeff elif mon == y: a3 = -coeff else: assert False return EllipticCurve([a1, a2, a3, a4, a6]) except AssertionError: raise NotImplementedError, "Construction of an elliptic curve from a generic cubic not yet implemented." if rings.is_Ring(x): if rings.is_RationalField(x): return ell_rational_field.EllipticCurve_rational_field(x, y) elif rings.is_FiniteField(x) or (rings.is_IntegerModRing(x) and x.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_pAdicField(x): return ell_padic_field.EllipticCurve_padic_field(x, y) elif rings.is_NumberField(x): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_Field(x): return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y) if isinstance(x, unicode): x = str(x) if isinstance(x, str): return ell_rational_field.EllipticCurve_rational_field(x) if rings.is_RingElement(x) and y is None: from sage.misc.misc import deprecation deprecation("'EllipticCurve(j)' is deprecated; use 'EllipticCurve_from_j(j)' or 'EllipticCurve(j=j)' instead.") # Fixed for all characteristics and cases by John Cremona j=x F=j.parent().fraction_field() char=F.characteristic() if char==2: if j==0: return EllipticCurve(F, [ 0, 0, 1, 0, 0 ]) else: return EllipticCurve(F, [ 1, 0, 0, 0, 1/j ]) if char==3: if j==0: return EllipticCurve(F, [ 0, 0, 0, 1, 0 ]) else: return EllipticCurve(F, [ 0, j, 0, 0, -j**2 ]) if j == 0: return EllipticCurve(F, [ 0, 0, 0, 0, 1 ]) if j == 1728: return EllipticCurve(F, [ 0, 0, 0, 1, 0 ]) k=j-1728 return EllipticCurve(F, [0,0,0,-3*j*k, -2*j*k**2]) if not isinstance(x,list): raise TypeError, "invalid input to EllipticCurve constructor" x = Sequence(x) if not (len(x) in [2,5]): raise ValueError, "sequence of coefficients must have length 2 or 5" R = x.universe() if isinstance(x[0], (rings.Rational, rings.Integer, int, long)): return ell_rational_field.EllipticCurve_rational_field(x, y) elif rings.is_NumberField(R): return ell_number_field.EllipticCurve_number_field(x, y) elif rings.is_pAdicField(R): return ell_padic_field.EllipticCurve_padic_field(x, y) elif rings.is_FiniteField(R) or (rings.is_IntegerModRing(R) and R.characteristic().is_prime()): return ell_finite_field.EllipticCurve_finite_field(x, y) elif rings.is_Field(R): return ell_field.EllipticCurve_field(x, y) return ell_generic.EllipticCurve_generic(x, y)