def _coerce_impl(self, f): """ Return the canonical coercion of ``f`` into this multivariate power series ring, if one is defined, or raise a TypeError. The rings that canonically coerce to this multivariate power series ring are: - this ring itself - a polynomial or power series ring in the same variables or a subset of these variables (possibly empty), over any base ring that canonically coerces into the base ring of this ring EXAMPLES:: sage: R.<t,u,v> = PowerSeriesRing(QQ); R Multivariate Power Series Ring in t, u, v over Rational Field sage: S1.<t,v> = PolynomialRing(ZZ); S1 Multivariate Polynomial Ring in t, v over Integer Ring sage: f1 = -t*v + 2*v^2 + v; f1 -t*v + 2*v^2 + v sage: R(f1) v - t*v + 2*v^2 sage: S2.<u,v> = PowerSeriesRing(ZZ); S2 Multivariate Power Series Ring in u, v over Integer Ring sage: f2 = -2*v^2 + 5*u*v^2 + S2.O(6); f2 -2*v^2 + 5*u*v^2 + O(u, v)^6 sage: R(f2) -2*v^2 + 5*u*v^2 + O(t, u, v)^6 sage: R2 = R.change_ring(GF(2)) sage: R2(f1) v + t*v sage: R2(f2) u*v^2 + O(t, u, v)^6 TESTS:: sage: R.<t,u,v> = PowerSeriesRing(QQ) sage: S1.<t,v> = PolynomialRing(ZZ) sage: f1 = S1.random_element() sage: g1 = R._coerce_impl(f1) sage: f1.parent() == R False sage: g1.parent() == R True """ P = f.parent() if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \ or is_PolynomialRing(P) or is_PowerSeriesRing(P): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return self(f) else: return self._coerce_try(f, [self.base_ring()])
def _coerce_impl(self, f): """ Return the canonical coercion of ``f`` into this multivariate power series ring, if one is defined, or raise a TypeError. The rings that canonically coerce to this multivariate power series ring are: - this ring itself - a polynomial or power series ring in the same variables or a subset of these variables (possibly empty), over any base ring that canonically coerces into the base ring of this ring EXAMPLES:: sage: R.<t,u,v> = PowerSeriesRing(QQ); R Multivariate Power Series Ring in t, u, v over Rational Field sage: S1.<t,v> = PolynomialRing(ZZ); S1 Multivariate Polynomial Ring in t, v over Integer Ring sage: f1 = -t*v + 2*v^2 + v; f1 -t*v + 2*v^2 + v sage: R(f1) v - t*v + 2*v^2 sage: S2.<u,v> = PowerSeriesRing(ZZ); S2 Multivariate Power Series Ring in u, v over Integer Ring sage: f2 = -2*v^2 + 5*u*v^2 + S2.O(6); f2 -2*v^2 + 5*u*v^2 + O(u, v)^6 sage: R(f2) -2*v^2 + 5*u*v^2 + O(t, u, v)^6 sage: R2 = R.change_ring(GF(2)) sage: R2(f1) v + t*v sage: R2(f2) u*v^2 + O(t, u, v)^6 TESTS:: sage: R.<t,u,v> = PowerSeriesRing(QQ) sage: S1.<t,v> = PolynomialRing(ZZ) sage: f1 = S1.random_element() sage: g1 = R._coerce_impl(f1) sage: f1.parent() == R False sage: g1.parent() == R True """ P = f.parent() if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \ or is_PolynomialRing(P) or is_PowerSeriesRing(P): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return self(f) else: return self._coerce_try(f,[self.base_ring()])
def _tower_variables(parent): result = [] n_vars = 0 while(is_PolynomialRing(parent) or is_MPolynomialRing(parent)): result += [str(gen) for gen in parent.gens()] n_vars += parent.ngens() parent = parent.base() return (parent,result, n_vars)
def AffineSpace(n, R=None, names='x'): r""" Return affine space of dimension `n` over the ring `R`. EXAMPLES: The dimension and ring can be given in either order:: sage: AffineSpace(3, QQ, 'x') Affine Space of dimension 3 over Rational Field sage: AffineSpace(5, QQ, 'x') Affine Space of dimension 5 over Rational Field sage: A = AffineSpace(2, QQ, names='XY'); A Affine Space of dimension 2 over Rational Field sage: A.coordinate_ring() Multivariate Polynomial Ring in X, Y over Rational Field Use the divide operator for base extension:: sage: AffineSpace(5, names='x')/GF(17) Affine Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`:: sage: AffineSpace(5, names='x') Affine Space of dimension 5 over Integer Ring There is also an affine space associated to each polynomial ring:: sage: R = GF(7)['x,y,z'] sage: A = AffineSpace(R); A Affine Space of dimension 3 over Finite Field of size 7 sage: A.coordinate_ring() is R True """ if is_MPolynomialRing(n) and R is None: R = n A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names()) A._coordinate_ring = R return A if isinstance(R, (int, long, Integer)): n, R = R, n if R is None: R = ZZ # default is the integers if names is None: if n == 0: names = '' else: raise TypeError( "You must specify the variables names of the coordinate ring.") names = normalize_names(n, names) if R in _Fields: if is_FiniteField(R): return AffineSpace_finite_field(n, R, names) else: return AffineSpace_field(n, R, names) return AffineSpace_generic(n, R, names)
def AffineSpace(n, R=None, names='x'): r""" Return affine space of dimension ``n`` over the ring ``R``. EXAMPLES: The dimension and ring can be given in either order:: sage: AffineSpace(3, QQ, 'x') Affine Space of dimension 3 over Rational Field sage: AffineSpace(5, QQ, 'x') Affine Space of dimension 5 over Rational Field sage: A = AffineSpace(2, QQ, names='XY'); A Affine Space of dimension 2 over Rational Field sage: A.coordinate_ring() Multivariate Polynomial Ring in X, Y over Rational Field Use the divide operator for base extension:: sage: AffineSpace(5, names='x')/GF(17) Affine Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`:: sage: AffineSpace(5, names='x') Affine Space of dimension 5 over Integer Ring There is also an affine space associated to each polynomial ring:: sage: R = GF(7)['x, y, z'] sage: A = AffineSpace(R); A Affine Space of dimension 3 over Finite Field of size 7 sage: A.coordinate_ring() is R True """ if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None: R = n A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names()) A._coordinate_ring = R return A if isinstance(R, integer_types + (Integer,)): n, R = R, n if R is None: R = ZZ # default is the integers if names is None: if n == 0: names = '' else: raise TypeError("you must specify the variables names of the coordinate ring") names = normalize_names(n, names) if R in _Fields: if is_FiniteField(R): return AffineSpace_finite_field(n, R, names) else: return AffineSpace_field(n, R, names) return AffineSpace_generic(n, R, names)
def multivariate_division_with_remainder(f, fs): """ Performs multivariate division with remainder, that is, returns quotients q_1, ..., q_s and a remainder r such that q_1 * f_1 + ... + q_s * f_s + r = f, and no monomial in r is divisible by any of lt(f_i). Both f and all fs must belong to the same multivariate polynomial ring. Parameters ---------- f : the numerator. fs : the list of denominators. Returns ------- qs: the quotients. r: the remainder, f rem (f1, ..., fs). """ poly_ring = f.parent() if (not is_PolynomialRing(poly_ring)) and ( not is_MPolynomialRing(poly_ring)): raise TypeError('f and the fs should belong to a polynomial ring') base_field = poly_ring.base_ring() if not base_field.is_field(): raise TypeError( 'f and the fs should belong to a polynomial ring over a field') if not all([poly_ring == g.parent()] for g in fs): raise ValueError("All polynomials must belong to the same ring") r = poly_ring(0) p = f q = [poly_ring(0)] * len(fs) while not p.is_zero(): any_divides = False for i in range(len(fs)): fi = fs[i] if fi.lt().divides(p.lt()): div, _ = p.lt().quo_rem(fi.lt()) q[i] += div p -= div * fi any_divides = True break if not any_divides: r += p.lt() p -= p.lt() return q, r
def buchberger_algorithm(I): """ Buchberger algorithm for the computation of a Groebner basis. Returns a list of polynomials that form a Groebner basis of the given ideal. Parameters ---------- I: an ideal of a multivariate polynomial ring over a field. Returns ------- The list of polynomials forming a Groebner basis. """ if not is_Ideal(I): raise TypeError('Argument should be an ideal') poly_ring = I.ring() if (not is_PolynomialRing(poly_ring)) and ( not is_MPolynomialRing(poly_ring)): raise TypeError('The ideal should be of a polynomial ring') base_field = I.base_ring() if not base_field.is_field(): raise TypeError( 'The ideal should be of a polynomial ring over a field') # Idea of the algorithm: we will check if the basis is already Groebner by checking that # S(gi, gj) rem (g1, ..., gs) = 0 for each pair (gi, gj). If it is not, we add that S(gi, gj) to the basis to force # it to be true. # Initialize G with the generators of the ideal G = list(I.basis) # It will finish by construction of the algorithm while True: S = [] G.sort(reverse=True) # Sorts with the polynomial ring ordering for (g1, g2) in __unordered_pairs(G): r = __s_polynomial(g1, g2) _, r = multivariate_division_with_remainder(r, G) if r != 0: S.append(r) # If S is empty, we already have a Groebner basis if not S: return G G.extend(S)
def is_member(f, I): """ Determines if the polynomial f is a member of the ideal I. Parameters ---------- f: a polynomial of a multivariate polynomial ring over a field. I: an ideal of the same polynomial ring. Returns ------- True if f is a member of the ideal I, False otherwise. """ if not is_Ideal(I): raise TypeError('Argument should be an ideal') poly_ring = I.ring() if not f.parent() == poly_ring: raise ValueError('f must belong to the same polynomial ring that the ideal belongs to') if (not is_PolynomialRing(poly_ring)) and (not is_MPolynomialRing(poly_ring)): raise TypeError('The ideal should be of a polynomial ring') base_field = I.base_ring() if not base_field.is_field(): raise TypeError('The ideal should be of a polynomial ring over a field') # Computation of a groebner basis G = buchberger_algorithm(I) # Since groebner basis have a unique remainder with multivariate division, f belongs to I <=> f rem G == 0 # Formalized on theorem 21.28 of Modern Computer Algebra _, rem = multivariate_division_with_remainder(f, G) return rem == 0
def Curve(F): """ Return the plane or space curve defined by `F`, where `F` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If `F` is in two variables the curve is affine, and if it is homogenous in `3` variables, then the curve is projective. EXAMPLE: A projective plane curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 EXAMPLE: Affine plane curves :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Curve over Rational Field defined by x^3 + y^3 + 1 EXAMPLE: A projective space curve :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Space Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 EXAMPLE: An affine space curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Space Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 EXAMPLE: We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 EXAMPLE: A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension `0`. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field EXAMPLE: In three variables, the defining equation must be homogeneous. If the parent polynomial ring is in three variables, then the defining ideal must be homogeneous. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial! The defining polynomial must always be nonzero:: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: Curve(0*x) Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero """ if is_AlgebraicScheme(F): return Curve(F.defining_polynomials()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) F = Sequence(F) P = F.universe() if not is_MPolynomialRing(P): raise TypeError("universe of F must be a multivariate polynomial ring") for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring()) A._coordinate_ring = P return AffineSpaceCurve_generic(A, F) A = ProjectiveSpace(P.ngens()-1, P.base_ring()) A._coordinate_ring = P return ProjectiveSpaceCurve_generic(A, F) if not is_MPolynomial(F): raise TypeError("F (=%s) must be a multivariate polynomial"%F) P = F.parent() k = F.base_ring() if F.parent().ngens() == 2: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") A2 = AffineSpace(2, P.base_ring()) A2._coordinate_ring = P if is_FiniteField(k): if k.is_prime_field(): return AffineCurve_prime_finite_field(A2, F) else: return AffineCurve_finite_field(A2, F) else: return AffineCurve_generic(A2, F) elif F.parent().ngens() == 3: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2 and k.is_field(): return Conic(F) if is_FiniteField(k): if k.is_prime_field(): return ProjectiveCurve_prime_finite_field(P2, F) else: return ProjectiveCurve_finite_field(P2, F) else: return ProjectiveCurve_generic(P2, F) else: raise TypeError("Number of variables of F (=%s) must be 2 or 3"%F)
def Curve(F): """ Return the plane or space curve defined by `F`, where `F` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If `F` is in two variables the curve is affine, and if it is homogenous in `3` variables, then the curve is projective. EXAMPLE: A projective plane curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 EXAMPLE: Affine plane curves :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Curve over Rational Field defined by x^3 + y^3 + 1 EXAMPLE: A projective space curve :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Space Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 EXAMPLE: An affine space curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Space Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 EXAMPLE: We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 EXAMPLE: A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension `0`. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field EXAMPLE: In three variables, the defining equation must be homogeneous. If the parent polynomial ring is in three variables, then the defining ideal must be homogeneous. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial! The defining polynomial must always be nonzero:: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: Curve(0*x) Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero """ if is_AlgebraicScheme(F): return Curve(F.defining_polynomials()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) F = Sequence(F) P = F.universe() if not is_MPolynomialRing(P): raise TypeError, "universe of F must be a multivariate polynomial ring" for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring()) A._coordinate_ring = P return AffineSpaceCurve_generic(A, F) A = ProjectiveSpace(P.ngens() - 1, P.base_ring()) A._coordinate_ring = P return ProjectiveSpaceCurve_generic(A, F) if not is_MPolynomial(F): raise TypeError, "F (=%s) must be a multivariate polynomial" % F P = F.parent() k = F.base_ring() if F.parent().ngens() == 2: if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" A2 = AffineSpace(2, P.base_ring()) A2._coordinate_ring = P if is_FiniteField(k): if k.is_prime_field(): return AffineCurve_prime_finite_field(A2, F) else: return AffineCurve_finite_field(A2, F) else: return AffineCurve_generic(A2, F) elif F.parent().ngens() == 3: if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2 and k.is_field(): return Conic(F) if is_FiniteField(k): if k.is_prime_field(): return ProjectiveCurve_prime_finite_field(P2, F) else: return ProjectiveCurve_finite_field(P2, F) else: return ProjectiveCurve_generic(P2, F) else: raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
def ProjectiveSpace(n, R=None, names='x'): r""" Return projective space of dimension `n` over the ring `R`. EXAMPLES: The dimension and ring can be given in either order. :: sage: ProjectiveSpace(3, QQ) Projective Space of dimension 3 over Rational Field sage: ProjectiveSpace(5, QQ) Projective Space of dimension 5 over Rational Field sage: P = ProjectiveSpace(2, QQ, names='XYZ'); P Projective Space of dimension 2 over Rational Field sage: P.coordinate_ring() Multivariate Polynomial Ring in X, Y, Z over Rational Field The divide operator does base extension. :: sage: ProjectiveSpace(5)/GF(17) Projective Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`. :: sage: ProjectiveSpace(5) Projective Space of dimension 5 over Integer Ring There is also an projective space associated each polynomial ring. :: sage: R = GF(7)['x,y,z'] sage: P = ProjectiveSpace(R); P Projective Space of dimension 2 over Finite Field of size 7 sage: P.coordinate_ring() Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 sage: P.coordinate_ring() is R True :: sage: ProjectiveSpace(3, Zp(5), 'y') Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20 :: sage: ProjectiveSpace(2,QQ,'x,y,z') Projective Space of dimension 2 over Rational Field :: sage: PS.<x,y>=ProjectiveSpace(1,CC) sage: PS Projective Space of dimension 1 over Complex Field with 53 bits of precision Projective spaces are not cached, i.e., there can be several with the same base ring and dimension (to facilitate gluing constructions). """ if is_MPolynomialRing(n) and R is None: A = ProjectiveSpace(n.ngens() - 1, n.base_ring()) A._coordinate_ring = n return A if isinstance(R, (int, long, Integer)): n, R = R, n if R is None: R = ZZ # default is the integers if R in _Fields: if is_FiniteField(R): return ProjectiveSpace_finite_field(n, R, names) if is_RationalField(R): return ProjectiveSpace_rational_field(n, R, names) else: return ProjectiveSpace_field(n, R, names) elif is_CommutativeRing(R): return ProjectiveSpace_ring(n, R, names) else: raise TypeError("R (=%s) must be a commutative ring" % R)
def _coerce_map_from_(self, P): """ The rings that canonically coerce to this multivariate power series ring are: - this ring itself - a polynomial or power series ring in the same variables or a subset of these variables (possibly empty), over any base ring that canonically coerces into this ring - any ring that coerces into the foreground polynomial ring of this ring EXAMPLES:: sage: A = GF(17)[['x','y']] sage: A.has_coerce_map_from(ZZ) True sage: A.has_coerce_map_from(ZZ['x']) True sage: A.has_coerce_map_from(ZZ['y','x']) True sage: A.has_coerce_map_from(ZZ[['x']]) True sage: A.has_coerce_map_from(ZZ[['y','x']]) True sage: A.has_coerce_map_from(ZZ['x','z']) False sage: A.has_coerce_map_from(GF(3)['x','y']) False sage: A.has_coerce_map_from(Frac(ZZ['y','x'])) False TESTS:: sage: M = PowerSeriesRing(ZZ,3,'x,y,z'); sage: M._coerce_map_from_(M) True sage: M._coerce_map_from_(M.remove_var(x)) True sage: M._coerce_map_from_(PowerSeriesRing(ZZ,x)) True sage: M._coerce_map_from_(PolynomialRing(ZZ,'x,z')) True sage: M._coerce_map_from_(PolynomialRing(ZZ,0,'')) True sage: M._coerce_map_from_(ZZ) True sage: M._coerce_map_from_(Zmod(13)) False sage: M._coerce_map_from_(PolynomialRing(ZZ,2,'x,t')) False sage: M._coerce_map_from_(PolynomialRing(Zmod(11),2,'x,y')) False sage: P = PolynomialRing(ZZ,3,'z') sage: H = PowerSeriesRing(P,4,'f'); H Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: H._coerce_map_from_(P) True sage: H._coerce_map_from_(P.remove_var(P.gen(1))) True sage: H._coerce_map_from_(PolynomialRing(ZZ,'z2,f0')) True """ if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \ or is_PolynomialRing(P) or is_PowerSeriesRing(P): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return True return self._poly_ring().has_coerce_map_from(P)
def __classcall_private__(cls, morphism_or_polys, domain=None): r""" Return the appropriate dynamical system on an affine scheme. TESTS:: sage: A.<x> = AffineSpace(ZZ,1) sage: A1.<z> = AffineSpace(CC,1) sage: H = End(A1) sage: f2 = H([z^2+1]) sage: f = DynamicalSystem_affine(f2, A) sage: f.domain() is A False :: sage: P1.<x,y> = ProjectiveSpace(QQ,1) sage: DynamicalSystem_affine([y, 2*x], domain=P1) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme sage: H = End(P1) sage: DynamicalSystem_affine(H([y, 2*x])) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme """ if isinstance(morphism_or_polys, SchemeMorphism_polynomial): morphism = morphism_or_polys R = morphism.base_ring() polys = list(morphism) domain = morphism.domain() if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if domain != morphism_or_polys.codomain(): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys,(list, tuple)): polys = list(morphism_or_polys) else: polys = [morphism_or_polys] # We now arrange for all of our list entries to lie in the same ring # Fraction field case first fraction_field = False for poly in polys: P = poly.parent() if is_FractionField(P): fraction_field = True break if fraction_field: K = P.base_ring().fraction_field() # Replace base ring with its fraction field P = P.ring().change_ring(K).fraction_field() polys = [P(poly) for poly in polys] else: # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. quotient_ring = False for poly in polys: P = poly.parent() if is_QuotientRing(P): quotient_ring = True break if quotient_ring: polys = [P(poly).lift() for poly in polys] else: poly_ring = False for poly in polys: P = poly.parent() if is_PolynomialRing(P) or is_MPolynomialRing(P): poly_ring = True break if poly_ring: polys = [P(poly) for poly in polys] if domain is None: f = polys[0] CR = f.parent() if CR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: CR = CR.ring() domain = AffineSpace(CR) R = domain.base_ring() if R is SR: raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain)
def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): """ Construct a new polynomial sequence object. INPUT: - ``arg1`` - a multivariate polynomial ring, an ideal or a matrix - ``arg2`` - an iterable object of parts or polynomials (default:``None``) - ``immutable`` - if ``True`` the sequence is immutable (default: ``False``) - ``cr`` - print a line break after each element (default: ``False``) - ``cr_str`` - print a line break after each element if 'str' is called (default: ``None``) EXAMPLES:: sage: P.<a,b,c,d> = PolynomialRing(GF(127),4) sage: I = sage.rings.ideal.Katsura(P) If a list of tuples is provided, those form the parts:: sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c, a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] sage: F.nparts() 2 If an ideal is provided, the generators are used:: sage: Sequence(I) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] If a list of polynomials is provided, the system has only one part:: sage: F = Sequence(I.gens(), I.ring()); F [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] sage: F.nparts() 1 """ from sage.matrix.matrix import is_Matrix if is_MPolynomialRing(arg1) or is_QuotientRing(arg1): ring = arg1 gens = arg2 elif is_MPolynomialRing(arg2) or is_QuotientRing(arg2): ring = arg2 gens = arg1 elif is_Matrix(arg1) and arg2 is None: ring = arg1.base_ring() gens = arg1.list() elif isinstance(arg1, MPolynomialIdeal) and arg2 is None: ring = arg1.ring() gens = arg1.gens() elif isinstance(arg1, (list,tuple,GeneratorType)) and arg2 is None: gens = arg1 try: e = iter(gens).next() except StopIteration: raise ValueError("Cannot determine ring from provided information.") if is_MPolynomial(e) or isinstance(e, QuotientRingElement): ring = e.parent() else: ring = iter(e).next().parent() else: raise TypeError("Cannot understand input.") try: e = iter(gens).next() if is_MPolynomial(e) or isinstance(e, QuotientRingElement): gens = tuple(gens) parts = (gens,) if not all(f.parent() is ring for f in gens): parts = ((ring(f) for f in gens),) else: parts = [] _gens = [] for part in gens: _part = [] for gen in part: if not gen.parent() is ring: ring(gen) _part.append(gen) _gens.extend(_part) parts.append(tuple(_part)) gens = _gens except StopIteration: gens = tuple() parts = ((),) k = ring.base_ring() try: c = k.characteristic() except NotImplementedError: c = -1 if c != 2: return PolynomialSequence_generic(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str) elif k.degree() == 1: return PolynomialSequence_gf2(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str) elif k.degree() > 1: return PolynomialSequence_gf2e(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str)
def __classcall_private__(cls, morphism_or_polys, domain=None): r""" Return the appropriate dynamical system on an affine scheme. TESTS:: sage: A.<x> = AffineSpace(ZZ,1) sage: A1.<z> = AffineSpace(CC,1) sage: H = End(A1) sage: f2 = H([z^2+1]) sage: f = DynamicalSystem_affine(f2, A) sage: f.domain() is A False :: sage: P1.<x,y> = ProjectiveSpace(QQ,1) sage: DynamicalSystem_affine([y, 2*x], domain=P1) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme sage: H = End(P1) sage: DynamicalSystem_affine(H([y, 2*x])) Traceback (most recent call last): ... ValueError: "domain" must be an affine scheme """ if isinstance(morphism_or_polys, SchemeMorphism_polynomial): morphism = morphism_or_polys R = morphism.base_ring() polys = list(morphism) domain = morphism.domain() if not is_AffineSpace(domain) and not isinstance( domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if domain != morphism_or_polys.codomain(): raise ValueError('domain and codomain do not agree') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain) elif isinstance(morphism_or_polys, (list, tuple)): polys = list(morphism_or_polys) else: polys = [morphism_or_polys] # We now arrange for all of our list entries to lie in the same ring # Fraction field case first fraction_field = False for poly in polys: P = poly.parent() if is_FractionField(P): fraction_field = True break if fraction_field: K = P.base_ring().fraction_field() # Replace base ring with its fraction field P = P.ring().change_ring(K).fraction_field() polys = [P(poly) for poly in polys] else: # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. quotient_ring = False for poly in polys: P = poly.parent() if is_QuotientRing(P): quotient_ring = True break if quotient_ring: polys = [P(poly).lift() for poly in polys] else: poly_ring = False for poly in polys: P = poly.parent() if is_PolynomialRing(P) or is_MPolynomialRing(P): poly_ring = True break if poly_ring: polys = [P(poly) for poly in polys] if domain is None: f = polys[0] CR = f.parent() if CR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: CR = CR.ring() domain = AffineSpace(CR) R = domain.base_ring() if R is SR: raise TypeError("Symbolic Ring cannot be the base ring") if not is_AffineSpace(domain) and not isinstance( domain, AlgebraicScheme_subscheme_affine): raise ValueError('"domain" must be an affine scheme') if R not in Fields(): return typecall(cls, polys, domain) if is_FiniteField(R): return DynamicalSystem_affine_finite_field(polys, domain) return DynamicalSystem_affine_field(polys, domain)
def Conic(base_field, F=None, names=None, unique=True): r""" Return the plane projective conic curve defined by ``F`` over ``base_field``. The input form ``Conic(F, names=None)`` is also accepted, in which case the fraction field of the base ring of ``F`` is used as base field. INPUT: - ``base_field`` -- The base field of the conic. - ``names`` -- a list, tuple, or comma separated string of three variable names specifying the names of the coordinate functions of the ambient space `\Bold{P}^3`. If not specified or read off from ``F``, then this defaults to ``'x,y,z'``. - ``F`` -- a polynomial, list, matrix, ternary quadratic form, or list or tuple of 5 points in the plane. If ``F`` is a polynomial or quadratic form, then the output is the curve in the projective plane defined by ``F = 0``. If ``F`` is a polynomial, then it must be a polynomial of degree at most 2 in 2 variables, or a homogeneous polynomial in of degree 2 in 3 variables. If ``F`` is a matrix, then the output is the zero locus of `(x,y,z) F (x,y,z)^t`. If ``F`` is a list of coefficients, then it has length 3 or 6 and gives the coefficients of the monomials `x^2, y^2, z^2` or all 6 monomials `x^2, xy, xz, y^2, yz, z^2` in lexicographic order. If ``F`` is a list of 5 points in the plane, then the output is a conic through those points. - ``unique`` -- Used only if ``F`` is a list of points in the plane. If the conic through the points is not unique, then raise ``ValueError`` if and only if ``unique`` is True OUTPUT: A plane projective conic curve defined by ``F`` over a field. EXAMPLES: Conic curves given by polynomials :: sage: X,Y,Z = QQ['X,Y,Z'].gens() sage: Conic(X^2 - X*Y + Y^2 - Z^2) Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2 sage: x,y = GF(7)['x,y'].gens() sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W') Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2 Conic curves given by matrices :: sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z') Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2 sage: x,y,z = GF(11)['x,y,z'].gens() sage: C = Conic(x^2+y^2-2*z^2); C Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 sage: Conic(C.symmetric_matrix(), 'x,y,z') Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 Conics given by coefficients :: sage: Conic(QQ, [1,2,3]) Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2 sage: Conic(GF(7), [1,2,3,4,5,6], 'X') Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2 The conic through a set of points :: sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2 sage: C.rational_point() (10 : 2 : 1) sage: C.point([3,4]) (3 : 4 : 1) sage: a=AffineSpace(GF(13),2) sage: Conic([a([x,x^2]) for x in range(5)]) Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z """ if not (base_field is None or isinstance(base_field, IntegralDomain)): if names is None: names = F F = base_field base_field = None if isinstance(F, (list,tuple)): if len(F) == 1: return Conic(base_field, F[0], names) if names is None: names = 'x,y,z' if len(F) == 5: L=[] for f in F: if isinstance(f, SchemeMorphism_point_affine): C = Sequence(f, universe = base_field) if len(C) != 2: raise TypeError("points in F (=%s) must be planar"%F) C.append(1) elif isinstance(f, SchemeMorphism_point_projective_field): C = Sequence(f, universe = base_field) elif isinstance(f, (list, tuple)): C = Sequence(f, universe = base_field) if len(C) == 2: C.append(1) else: raise TypeError("F (=%s) must be a sequence of planar " \ "points" % F) if len(C) != 3: raise TypeError("points in F (=%s) must be planar" % F) P = C.universe() if not isinstance(P, IntegralDomain): raise TypeError("coordinates of points in F (=%s) must " \ "be in an integral domain" % F) L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2, C[1]*C[2], C[2]**2], P.fraction_field())) M=Matrix(L) if unique and M.rank() != 5: raise ValueError("points in F (=%s) do not define a unique " \ "conic" % F) con = Conic(base_field, Sequence(M.right_kernel().gen()), names) con.point(F[0]) return con F = Sequence(F, universe = base_field) base_field = F.universe().fraction_field() temp_ring = PolynomialRing(base_field, 3, names) (x,y,z) = temp_ring.gens() if len(F) == 3: return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2) if len(F) == 6: return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \ F[4]*y*z + F[5]*z**2) raise TypeError("F (=%s) must be a sequence of 3 or 6" \ "coefficients" % F) if is_QuadraticForm(F): F = F.matrix() if is_Matrix(F) and F.is_square() and F.ncols() == 3: if names is None: names = 'x,y,z' temp_ring = PolynomialRing(F.base_ring(), 3, names) F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) if not is_MPolynomial(F): raise TypeError("F (=%s) must be a three-variable polynomial or " \ "a sequence of points or coefficients" % F) if F.total_degree() != 2: raise TypeError("F (=%s) must have degree 2" % F) if base_field is None: base_field = F.base_ring() if not isinstance(base_field, IntegralDomain): raise ValueError("Base field (=%s) must be a field" % base_field) base_field = base_field.fraction_field() if names is None: names = F.parent().variable_names() pol_ring = PolynomialRing(base_field, 3, names) if F.parent().ngens() == 2: (x,y,z) = pol_ring.gens() F = pol_ring(F(x/z,y/z)*z**2) if F == 0: raise ValueError("F must be nonzero over base field %s" % base_field) if F.total_degree() != 2: raise TypeError("F (=%s) must have degree 2 over base field %s" % \ (F, base_field)) if F.parent().ngens() == 3: P2 = ProjectiveSpace(2, base_field, names) if is_PrimeFiniteField(base_field): return ProjectiveConic_prime_finite_field(P2, F) if is_FiniteField(base_field): return ProjectiveConic_finite_field(P2, F) if is_RationalField(base_field): return ProjectiveConic_rational_field(P2, F) if is_NumberField(base_field): return ProjectiveConic_number_field(P2, F) if is_FractionField(base_field) and (is_PolynomialRing(base_field.ring()) or is_MPolynomialRing(base_field.ring())): return ProjectiveConic_rational_function_field(P2, F) return ProjectiveConic_field(P2, F) raise TypeError("Number of variables of F (=%s) must be 2 or 3" % F)
def chord_and_tangent(F, P): """ Use the chord and tangent method to get another point on a cubic. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. OUTPUT: Another point satisfying the equation ``F``. EXAMPLES:: sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent sage: F = x^3+y^3+60*z^3 sage: chord_and_tangent(F, [1,-1,0]) [1, -1, 0] sage: F = x^3+7*y^3+64*z^3 sage: p0 = [2,2,-1] sage: p1 = chord_and_tangent(F, p0); p1 [-5, 3, -1] sage: p2 = chord_and_tangent(F, p1); p2 [1265, -183, -314] TESTS:: sage: F(p2) 0 sage: map(type, p2) [<type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>] See :trac:`16068`:: sage: F = x**3 - 4*x**2*y - 65*x*y**2 + 3*x*y*z - 76*y*z**2 sage: chord_and_tangent(F, [0, 1, 0]) [0, 0, -1] """ # check the input R = F.parent() if not is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('%s is not a polynomial in three variables'%F) if not F.is_homogeneous(): raise TypeError('%s is not a homogeneous polynomial'%F) x, y, z = R.gens() if len(P) != 3: raise TypeError('%s is not a projective point'%P) K = R.base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot coerce %s into %s'%(P,K)) if F(P) != 0: raise ValueError('%s is not a point on %s'%(P,F)) # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # if dF/dy(P) = 0, change variables so that dF/dy != 0 if dy == 0: if dx != 0: g = F.substitute({x:y, y:x}) Q = [P[1], P[0], P[2]] R = chord_and_tangent(g, Q) return [R[1], R[0], R[2]] elif dz != 0: g = F.substitute({y:z, z:y}) Q = [P[0], P[2], P[1]] R = chord_and_tangent(g, Q) return [R[0], R[2], R[1]] else: raise ValueError('%s is singular at %s'%(F, P)) # t will be our choice of parmeter of the tangent plane # dx*(x-P[0]) + dy*(y-P[1]) + dz*(z-P[2]) # through the point P t = rings.PolynomialRing(K, 't').gen(0) Ft = F(dy*t+P[0], -dx*t+P[1], P[2]) if Ft == 0: # (dy, -dx, 0) is projectively equivalent to P # then (0, -dz, dy) is not projectively equivalent to P g = F.substitute({x:z, z:x}) Q = [P[2], P[1], P[0]] R = chord_and_tangent(g, Q) return [R[2], R[1], R[0]] # Ft has a double zero at t=0 by construction, which we now remove Ft = Ft // t**2 # first case: the third point is at t=infinity if Ft.is_constant(): return projective_point([dy, -dx, K(0)]) # second case: the third point is at finite t else: assert Ft.degree() == 1 t0 = Ft.roots()[0][0] return projective_point([dy*t0+P[0], -dx*t0+P[1], P[2]])
def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False): """ A mutable list of elements with a common guaranteed universe, which can be set immutable. A universe is either an object that supports coercion (e.g., a parent), or a category. INPUT: - ``x`` - a list or tuple instance - ``universe`` - (default: None) the universe of elements; if None determined using canonical coercions and the entire list of elements. If list is empty, is category Objects() of all objects. - ``check`` -- (default: True) whether to coerce the elements of x into the universe - ``immutable`` - (default: True) whether or not this sequence is immutable - ``cr`` - (default: False) if True, then print a carriage return after each comma when printing this sequence. - ``cr_str`` - (default: False) if True, then print a carriage return after each comma when calling ``str()`` on this sequence. - ``use_sage_types`` -- (default: False) if True, coerce the built-in Python numerical types int, long, float, complex to the corresponding Sage types (this makes functions like vector() more flexible) OUTPUT: - a sequence EXAMPLES:: sage: v = Sequence(range(10)) sage: v.universe() <type 'int'> sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] We can request that the built-in Python numerical types be coerced to Sage objects:: sage: v = Sequence(range(10), use_sage_types=True) sage: v.universe() Integer Ring sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] You can also use seq for "Sequence", which is identical to using Sequence:: sage: v = seq([1,2,1/1]); v [1, 2, 1] sage: v.universe() Rational Field sage: v.parent() Category of sequences in Rational Field sage: v.parent()([3,4/3]) [3, 4/3] Note that assignment coerces if possible,:: sage: v = Sequence(range(10), ZZ) sage: a = QQ(5) sage: v[3] = a sage: parent(v[3]) Integer Ring sage: parent(a) Rational Field sage: v[3] = 2/3 Traceback (most recent call last): ... TypeError: no conversion of this rational to integer Sequences can be used absolutely anywhere lists or tuples can be used:: sage: isinstance(v, list) True Sequence can be immutable, so entries can't be changed:: sage: v = Sequence([1,2,3], immutable=True) sage: v.is_immutable() True sage: v[0] = 5 Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. Only immutable sequences are hashable (unlike Python lists), though the hashing is potentially slow, since it first involves conversion of the sequence to a tuple, and returning the hash of that.:: sage: v = Sequence(range(10), ZZ, immutable=True) sage: hash(v) 1591723448 # 32-bit -4181190870548101704 # 64-bit If you really know what you are doing, you can circumvent the type checking (for an efficiency gain):: sage: list.__setitem__(v, int(1), 2/3) # bad circumvention sage: v [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9] sage: list.__setitem__(v, int(1), int(2)) # not so bad circumvention You can make a sequence with a new universe from an old sequence.:: sage: w = Sequence(v, QQ) sage: w [0, 2, 2, 3, 4, 5, 6, 7, 8, 9] sage: w.universe() Rational Field sage: w[1] = 2/3 sage: w [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9] Sequences themselves live in a category, the category of all sequences in the given universe.:: sage: w.category() Category of sequences in Rational Field This is also the parent of any sequence:: sage: w.parent() Category of sequences in Rational Field The default universe for any sequence, if no compatible parent structure can be found, is the universe of all Sage objects. This example illustrates how every element of a list is taken into account when constructing a sequence.:: sage: v = Sequence([1,7,6,GF(5)(3)]); v [1, 2, 1, 3] sage: v.universe() Finite Field of size 5 sage: v.parent() Category of sequences in Finite Field of size 5 sage: v.parent()([7,8,9]) [2, 3, 4] """ from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal if isinstance(x, Sequence_generic) and universe is None: universe = x.universe() x = list(x) if isinstance(x, MPolynomialIdeal) and universe is None: universe = x.ring() x = x.gens() if universe is None: if not isinstance(x, (list, tuple)): x = list(x) #raise TypeError("x must be a list or tuple") if len(x) == 0: import sage.categories.all universe = sage.categories.all.Objects() else: import sage.structure.element as coerce y = x x = list(x) # make a copy, or we'd change the type of the elements of x, which would be bad. if use_sage_types: # convert any Python built-in numerical types to Sage objects from sage.rings.integer_ring import ZZ from sage.rings.real_double import RDF from sage.rings.complex_double import CDF for i in range(len(x)): if isinstance(x[i], int) or isinstance(x[i], long): x[i] = ZZ(x[i]) elif isinstance(x[i], float): x[i] = RDF(x[i]) elif isinstance(x[i], complex): x[i] = CDF(x[i]) # start the pairwise coercion for i in range(len(x)-1): try: x[i], x[i+1] = coerce.canonical_coercion(x[i],x[i+1]) except TypeError: import sage.categories.all universe = sage.categories.all.Objects() x = list(y) check = False # no point break if universe is None: # no type errors raised. universe = coerce.parent(x[len(x)-1]) from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.quotient_ring import is_QuotientRing from sage.rings.polynomial.pbori import BooleanMonomialMonoid if is_MPolynomialRing(universe) or \ (is_QuotientRing(universe) and is_MPolynomialRing(universe.cover_ring())) or \ isinstance(universe, BooleanMonomialMonoid): from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence try: return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) except (TypeError,AttributeError): return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types) else: return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types)
def Curve(F, A=None): """ Return the plane or space curve defined by ``F``, where ``F`` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If no ambient space is passed in for ``A``, and if ``F`` is not an algebraic scheme, a new ambient space is constructed. Also not specifying an ambient space will cause the curve to be defined in either affine or projective space based on properties of ``F``. In particular, if ``F`` contains a nonhomogenous polynomial, the curve is affine, and if ``F`` consists of homogenous polynomials, then the curve is projective. INPUT: - ``F`` -- a multivariate polynomial, or a list or tuple of polynomials, or an algebraic scheme. - ``A`` -- (default: None) an ambient space in which to create the curve. EXAMPLES: A projective plane curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Plane Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 EXAMPLES: Affine plane curves :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Plane Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Plane Curve over Rational Field defined by x^3 + y^3 + 1 EXAMPLES: A projective space curve :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 EXAMPLES: An affine space curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 EXAMPLES: We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Plane Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 EXAMPLES: A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Plane Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension `0`. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field EXAMPLES: In three variables, the defining equation must be homogeneous. If the parent polynomial ring is in three variables, then the defining ideal must be homogeneous. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial The defining polynomial must always be nonzero:: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: Curve(0*x) Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: C = Curve([y - x^2, z - x^3], A) sage: A == C.ambient_space() True """ if not A is None: if not isinstance(F, (list, tuple)): return Curve([F], A) if not is_AmbientSpace(A): raise TypeError("A (=%s) must be either an affine or projective space"%A) if not all([f.parent() == A.coordinate_ring() for f in F]): raise TypeError("F (=%s) must be a list or tuple of polynomials of the coordinate ring of " \ "A (=%s)"%(F, A)) n = A.dimension_relative() if n < 2: raise TypeError("A (=%s) must be either an affine or projective space of dimension > 1"%A) # there is no dimension check when initializing a plane curve, so check here that F consists # of a single nonconstant polynomial if n == 2: if len(F) != 1 or F[0] == 0 or not is_MPolynomial(F[0]): raise TypeError("F (=%s) must consist of a single nonconstant polynomial to define a plane curve"%(F,)) if is_AffineSpace(A): if n > 2: return AffineCurve(A, F) k = A.base_ring() if is_FiniteField(k): if k.is_prime_field(): return AffinePlaneCurve_prime_finite_field(A, F[0]) return AffinePlaneCurve_finite_field(A, F[0]) return AffinePlaneCurve(A, F[0]) elif is_ProjectiveSpace(A): if not all([f.is_homogeneous() for f in F]): raise TypeError("polynomials defining a curve in a projective space must be homogeneous") if n > 2: return ProjectiveCurve(A, F) k = A.base_ring() if is_FiniteField(k): if k.is_prime_field(): return ProjectivePlaneCurve_prime_finite_field(A, F[0]) return ProjectivePlaneCurve_finite_field(A, F[0]) return ProjectivePlaneCurve(A, F[0]) if is_AlgebraicScheme(F): return Curve(F.defining_polynomials(), F.ambient_space()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) F = Sequence(F) P = F.universe() if not is_MPolynomialRing(P): raise TypeError("universe of F must be a multivariate polynomial ring") for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring()) A._coordinate_ring = P return AffineCurve(A, F) A = ProjectiveSpace(P.ngens()-1, P.base_ring()) A._coordinate_ring = P return ProjectiveCurve(A, F) if not is_MPolynomial(F): raise TypeError("F (=%s) must be a multivariate polynomial"%F) P = F.parent() k = F.base_ring() if F.parent().ngens() == 2: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") A2 = AffineSpace(2, P.base_ring()) A2._coordinate_ring = P if is_FiniteField(k): if k.is_prime_field(): return AffinePlaneCurve_prime_finite_field(A2, F) else: return AffinePlaneCurve_finite_field(A2, F) else: return AffinePlaneCurve(A2, F) elif F.parent().ngens() == 3: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2 and k.is_field(): return Conic(F) if is_FiniteField(k): if k.is_prime_field(): return ProjectivePlaneCurve_prime_finite_field(P2, F) else: return ProjectivePlaneCurve_finite_field(P2, F) else: return ProjectivePlaneCurve(P2, F) else: raise TypeError("Number of variables of F (=%s) must be 2 or 3"%F)
def Curve(F, A=None): """ Return the plane or space curve defined by ``F``, where ``F`` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If no ambient space is passed in for ``A``, and if ``F`` is not an algebraic scheme, a new ambient space is constructed. Also not specifying an ambient space will cause the curve to be defined in either affine or projective space based on properties of ``F``. In particular, if ``F`` contains a nonhomogenous polynomial, the curve is affine, and if ``F`` consists of homogenous polynomials, then the curve is projective. INPUT: - ``F`` -- a multivariate polynomial, or a list or tuple of polynomials, or an algebraic scheme. - ``A`` -- (default: None) an ambient space in which to create the curve. EXAMPLES: A projective plane curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Plane Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 Affine plane curves. :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Plane Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Plane Curve over Rational Field defined by x^3 + y^3 + 1 A projective space curve. :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 An affine space curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Plane Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Plane Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension 0. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field If only a polynomial in three variables is given, then it must be homogeneous such that a projective curve is constructed. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial An ambient space can be specified to construct a space curve in an affine or a projective space. :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: C = Curve([y - x^2, z - x^3], A) sage: C Affine Curve over Rational Field defined by -x^2 + y, -x^3 + z sage: A == C.ambient_space() True The defining polynomial must be nonzero unless the ambient space itself is of dimension 1. :: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: S = P1.coordinate_ring() sage: Curve(S(0), P1) Projective Line over Finite Field of size 5 sage: Curve(P1) Projective Line over Finite Field of size 5 :: sage: A1.<x> = AffineSpace(1, QQ) sage: R = A1.coordinate_ring() sage: Curve(R(0), A1) Affine Line over Rational Field sage: Curve(A1) Affine Line over Rational Field """ if A is None: if is_AmbientSpace(F) and F.dimension() == 1: return Curve(F.coordinate_ring().zero(), F) if is_AlgebraicScheme(F): return Curve(F.defining_polynomials(), F.ambient_space()) if isinstance(F, (list, tuple)): P = Sequence(F).universe() if not is_MPolynomialRing(P): raise TypeError("universe of F must be a multivariate polynomial ring") for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring(), names=P.variable_names()) A._coordinate_ring = P break else: A = ProjectiveSpace(P.ngens()-1, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P elif is_MPolynomial(F): # define a plane curve P = F.parent() k = F.base_ring() if not k.is_field(): if k.is_integral_domain(): # upgrade to a field P = P.change_ring(k.fraction_field()) F = P(F) k = F.base_ring() else: raise TypeError("not a multivariate polynomial over a field or an integral domain") if F.parent().ngens() == 2: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") A = AffineSpace(2, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P elif F.parent().ngens() == 3: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") # special case: construct a conic curve if F.total_degree() == 2 and k.is_field(): return Conic(k, F) A = ProjectiveSpace(2, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P elif F.parent().ngens() == 1: if not F.is_zero(): raise ValueError("defining polynomial of curve must be zero " "if the ambient space is of dimension 1") A = AffineSpace(1, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P else: raise TypeError("number of variables of F (={}) must be 2 or 3".format(F)) F = [F] else: raise TypeError("F (={}) must be a multivariate polynomial".format(F)) else: if not is_AmbientSpace(A): raise TypeError("ambient space must be either an affine or projective space") if not isinstance(F, (list, tuple)): F = [F] if not all(f.parent() == A.coordinate_ring() for f in F): raise TypeError("need a list of polynomials of the coordinate ring of {}".format(A)) n = A.dimension_relative() if n < 1: raise TypeError("ambient space should be an affine or projective space of positive dimension") k = A.base_ring() if is_AffineSpace(A): if n != 2: if is_FiniteField(k): if A.coordinate_ring().ideal(F).is_prime(): return IntegralAffineCurve_finite_field(A, F) if k in Fields(): if k == QQ and A.coordinate_ring().ideal(F).is_prime(): return IntegralAffineCurve(A, F) return AffineCurve_field(A, F) return AffineCurve(A, F) if not (len(F) == 1 and F[0] != 0 and F[0].degree() > 0): raise TypeError("need a single nonconstant polynomial to define a plane curve") F = F[0] if is_FiniteField(k): if _is_irreducible_and_reduced(F): return IntegralAffinePlaneCurve_finite_field(A, F) return AffinePlaneCurve_finite_field(A, F) if k in Fields(): if k == QQ and _is_irreducible_and_reduced(F): return IntegralAffinePlaneCurve(A, F) return AffinePlaneCurve_field(A, F) return AffinePlaneCurve(A, F) elif is_ProjectiveSpace(A): if n != 2: if not all(f.is_homogeneous() for f in F): raise TypeError("polynomials defining a curve in a projective space must be homogeneous") if is_FiniteField(k): if A.coordinate_ring().ideal(F).is_prime(): return IntegralProjectiveCurve_finite_field(A, F) if k in Fields(): if k == QQ and A.coordinate_ring().ideal(F).is_prime(): return IntegralProjectiveCurve(A, F) return ProjectiveCurve_field(A, F) return ProjectiveCurve(A, F) # There is no dimension check when initializing a plane curve, so check # here that F consists of a single nonconstant polynomial. if not (len(F) == 1 and F[0] != 0 and F[0].degree() > 0): raise TypeError("need a single nonconstant polynomial to define a plane curve") F = F[0] if not F.is_homogeneous(): raise TypeError("{} is not a homogeneous polynomial".format(F)) if is_FiniteField(k): if _is_irreducible_and_reduced(F): return IntegralProjectivePlaneCurve_finite_field(A, F) return ProjectivePlaneCurve_finite_field(A, F) if k in Fields(): if k == QQ and _is_irreducible_and_reduced(F): return IntegralProjectivePlaneCurve(A, F) return ProjectivePlaneCurve_field(A, F) return ProjectivePlaneCurve(A, F) else: raise TypeError('ambient space neither affine nor projective')
def AffineSpace(n, R=None, names='x', ambient_projective_space=None, default_embedding_index=None): r""" Return affine space of dimension ``n`` over the ring ``R``. EXAMPLES: The dimension and ring can be given in either order:: sage: AffineSpace(3, QQ, 'x') Affine Space of dimension 3 over Rational Field sage: AffineSpace(5, QQ, 'x') Affine Space of dimension 5 over Rational Field sage: A = AffineSpace(2, QQ, names='XY'); A Affine Space of dimension 2 over Rational Field sage: A.coordinate_ring() Multivariate Polynomial Ring in X, Y over Rational Field Use the divide operator for base extension:: sage: AffineSpace(5, names='x')/GF(17) Affine Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`:: sage: AffineSpace(5, names='x') Affine Space of dimension 5 over Integer Ring There is also an affine space associated to each polynomial ring:: sage: R = GF(7)['x, y, z'] sage: A = AffineSpace(R); A Affine Space of dimension 3 over Finite Field of size 7 sage: A.coordinate_ring() is R True """ if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None: R = n A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names()) A._coordinate_ring = R return A if isinstance(R, integer_types + (Integer,)): n, R = R, n if R is None: R = ZZ # default is the integers if names is None: if n == 0: names = '' else: raise TypeError("you must specify the variables names of the coordinate ring") names = normalize_names(n, names) if default_embedding_index is not None and ambient_projective_space is None: from sage.schemes.projective.projective_space import ProjectiveSpace ambient_projective_space = ProjectiveSpace(n, R) if R in _Fields: if is_FiniteField(R): return AffineSpace_finite_field(n, R, names, ambient_projective_space, default_embedding_index) else: return AffineSpace_field(n, R, names, ambient_projective_space, default_embedding_index) return AffineSpace_generic(n, R, names, ambient_projective_space, default_embedding_index)
def ProjectiveSpace(n, R=None, names='x'): r""" Return projective space of dimension `n` over the ring `R`. EXAMPLES: The dimension and ring can be given in either order. :: sage: ProjectiveSpace(3, QQ) Projective Space of dimension 3 over Rational Field sage: ProjectiveSpace(5, QQ) Projective Space of dimension 5 over Rational Field sage: P = ProjectiveSpace(2, QQ, names='XYZ'); P Projective Space of dimension 2 over Rational Field sage: P.coordinate_ring() Multivariate Polynomial Ring in X, Y, Z over Rational Field The divide operator does base extension. :: sage: ProjectiveSpace(5)/GF(17) Projective Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`. :: sage: ProjectiveSpace(5) Projective Space of dimension 5 over Integer Ring There is also an projective space associated each polynomial ring. :: sage: R = GF(7)['x,y,z'] sage: P = ProjectiveSpace(R); P Projective Space of dimension 2 over Finite Field of size 7 sage: P.coordinate_ring() Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 sage: P.coordinate_ring() is R True :: sage: ProjectiveSpace(3, Zp(5), 'y') Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20 :: sage: ProjectiveSpace(2,QQ,'x,y,z') Projective Space of dimension 2 over Rational Field :: sage: PS.<x,y>=ProjectiveSpace(1,CC) sage: PS Projective Space of dimension 1 over Complex Field with 53 bits of precision Projective spaces are not cached, i.e., there can be several with the same base ring and dimension (to facilitate gluing constructions). """ if is_MPolynomialRing(n) and R is None: A = ProjectiveSpace(n.ngens()-1, n.base_ring()) A._coordinate_ring = n return A if isinstance(R, (int, long, Integer)): n, R = R, n if R is None: R = ZZ # default is the integers if R in _Fields: if is_FiniteField(R): return ProjectiveSpace_finite_field(n, R, names) if is_RationalField(R): return ProjectiveSpace_rational_field(n, R, names) else: return ProjectiveSpace_field(n, R, names) elif is_CommutativeRing(R): return ProjectiveSpace_ring(n, R, names) else: raise TypeError("R (=%s) must be a commutative ring"%R)
def Curve(F, A=None): """ Return the plane or space curve defined by ``F``, where ``F`` can be either a multivariate polynomial, a list or tuple of polynomials, or an algebraic scheme. If no ambient space is passed in for ``A``, and if ``F`` is not an algebraic scheme, a new ambient space is constructed. Also not specifying an ambient space will cause the curve to be defined in either affine or projective space based on properties of ``F``. In particular, if ``F`` contains a nonhomogenous polynomial, the curve is affine, and if ``F`` consists of homogenous polynomials, then the curve is projective. INPUT: - ``F`` -- a multivariate polynomial, or a list or tuple of polynomials, or an algebraic scheme. - ``A`` -- (default: None) an ambient space in which to create the curve. EXAMPLE: A projective plane curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3); C Projective Plane Curve over Rational Field defined by x^3 + y^3 + z^3 sage: C.genus() 1 EXAMPLE: Affine plane curves :: sage: x,y = GF(7)['x,y'].gens() sage: C = Curve(y^2 + x^3 + x^10); C Affine Plane Curve over Finite Field of size 7 defined by x^10 + x^3 + y^2 sage: C.genus() 0 sage: x, y = QQ['x,y'].gens() sage: Curve(x^3 + y^3 + 1) Affine Plane Curve over Rational Field defined by x^3 + y^3 + 1 EXAMPLE: A projective space curve :: sage: x,y,z,w = QQ['x,y,z,w'].gens() sage: C = Curve([x^3 + y^3 - z^3 - w^3, x^5 - y*z^4]); C Projective Curve over Rational Field defined by x^3 + y^3 - z^3 - w^3, x^5 - y*z^4 sage: C.genus() 13 EXAMPLE: An affine space curve :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve([y^2 + x^3 + x^10 + z^7, x^2 + y^2]); C Affine Curve over Rational Field defined by x^10 + z^7 + x^3 + y^2, x^2 + y^2 sage: C.genus() 47 EXAMPLE: We can also make non-reduced non-irreducible curves. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve((x-y)*(x+y)) Projective Conic Curve over Rational Field defined by x^2 - y^2 sage: Curve((x-y)^2*(x+y)^2) Projective Plane Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4 EXAMPLE: A union of curves is a curve. :: sage: x,y,z = QQ['x,y,z'].gens() sage: C = Curve(x^3 + y^3 + z^3) sage: D = Curve(x^4 + y^4 + z^4) sage: C.union(D) Projective Plane Curve over Rational Field defined by x^7 + x^4*y^3 + x^3*y^4 + y^7 + x^4*z^3 + y^4*z^3 + x^3*z^4 + y^3*z^4 + z^7 The intersection is not a curve, though it is a scheme. :: sage: X = C.intersection(D); X Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^3 + y^3 + z^3, x^4 + y^4 + z^4 Note that the intersection has dimension `0`. :: sage: X.dimension() 0 sage: I = X.defining_ideal(); I Ideal (x^3 + y^3 + z^3, x^4 + y^4 + z^4) of Multivariate Polynomial Ring in x, y, z over Rational Field EXAMPLE: In three variables, the defining equation must be homogeneous. If the parent polynomial ring is in three variables, then the defining ideal must be homogeneous. :: sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Conic Curve over Rational Field defined by x^2 + y^2 sage: Curve(x^2+y^2+z) Traceback (most recent call last): ... TypeError: x^2 + y^2 + z is not a homogeneous polynomial The defining polynomial must always be nonzero:: sage: P1.<x,y> = ProjectiveSpace(1,GF(5)) sage: Curve(0*x) Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero :: sage: A.<x,y,z> = AffineSpace(QQ, 3) sage: C = Curve([y - x^2, z - x^3], A) sage: A == C.ambient_space() True """ if not A is None: if not isinstance(F, (list, tuple)): return Curve([F], A) if not is_AmbientSpace(A): raise TypeError( "A (=%s) must be either an affine or projective space" % A) if not all([f.parent() == A.coordinate_ring() for f in F]): raise TypeError("F (=%s) must be a list or tuple of polynomials of the coordinate ring of " \ "A (=%s)"%(F, A)) n = A.dimension_relative() if n < 2: raise TypeError( "A (=%s) must be either an affine or projective space of dimension > 1" % A) # there is no dimension check when initializing a plane curve, so check here that F consists # of a single nonconstant polynomial if n == 2: if len(F) != 1 or F[0] == 0 or not is_MPolynomial(F[0]): raise TypeError( "F (=%s) must consist of a single nonconstant polynomial to define a plane curve" % (F, )) if is_AffineSpace(A): if n > 2: return AffineCurve(A, F) k = A.base_ring() if is_FiniteField(k): if k.is_prime_field(): return AffinePlaneCurve_prime_finite_field(A, F[0]) return AffinePlaneCurve_finite_field(A, F[0]) return AffinePlaneCurve(A, F[0]) elif is_ProjectiveSpace(A): if not all([f.is_homogeneous() for f in F]): raise TypeError( "polynomials defining a curve in a projective space must be homogeneous" ) if n > 2: return ProjectiveCurve(A, F) k = A.base_ring() if is_FiniteField(k): if k.is_prime_field(): return ProjectivePlaneCurve_prime_finite_field(A, F[0]) return ProjectivePlaneCurve_finite_field(A, F[0]) return ProjectivePlaneCurve(A, F[0]) if is_AlgebraicScheme(F): return Curve(F.defining_polynomials(), F.ambient_space()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) F = Sequence(F) P = F.universe() if not is_MPolynomialRing(P): raise TypeError( "universe of F must be a multivariate polynomial ring") for f in F: if not f.is_homogeneous(): A = AffineSpace(P.ngens(), P.base_ring()) A._coordinate_ring = P return AffineCurve(A, F) A = ProjectiveSpace(P.ngens() - 1, P.base_ring()) A._coordinate_ring = P return ProjectiveCurve(A, F) if not is_MPolynomial(F): raise TypeError("F (=%s) must be a multivariate polynomial" % F) P = F.parent() k = F.base_ring() if F.parent().ngens() == 2: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") A2 = AffineSpace(2, P.base_ring()) A2._coordinate_ring = P if is_FiniteField(k): if k.is_prime_field(): return AffinePlaneCurve_prime_finite_field(A2, F) else: return AffinePlaneCurve_finite_field(A2, F) else: return AffinePlaneCurve(A2, F) elif F.parent().ngens() == 3: if F == 0: raise ValueError("defining polynomial of curve must be nonzero") P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2 and k.is_field(): return Conic(F) if is_FiniteField(k): if k.is_prime_field(): return ProjectivePlaneCurve_prime_finite_field(P2, F) else: return ProjectivePlaneCurve_finite_field(P2, F) else: return ProjectivePlaneCurve(P2, F) else: raise TypeError("Number of variables of F (=%s) must be 2 or 3" % F)
def EllipticCurve_from_cubic(F, P, morphism=True): r""" Construct an elliptic curve from a ternary cubic with a rational point. If you just want the Weierstrass form and are not interested in the morphism then it is easier to use :func:`~sage.schemes.elliptic_curves.jacobian.Jacobian` instead. This will construct the same elliptic curve but you don't have to supply the point ``P``. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. Need not be a flex, but see caveat on output. - ``morphism`` -- boolean (default: ``True``). Whether to return the morphism or just the elliptic curve. OUTPUT: An elliptic curve in long Weierstrass form isomorphic to the curve `F=0`. If ``morphism=True`` is passed, then a birational equivalence between F and the Weierstrass curve is returned. If the point happens to be a flex, then this is an isomorphism. EXAMPLES: First we find that the Fermat cubic is isomorphic to the curve with Cremona label 27a1:: sage: R.<x,y,z> = QQ[] sage: cubic = x^3+y^3+z^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 1/3*y = x^3 - x^2 - 1/3*x - 1/27 over Rational Field sage: E.cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label() '27a1' Next we find the minimal model and conductor of the Jacobian of the Selmer curve:: sage: R.<a,b,c> = QQ[] sage: cubic = a^3+b^3+60*c^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: E.conductor() 24300 We can also get the birational equivalence to and from the Weierstrass form. We start with an example where ``P`` is a flex and the equivalence is an isomorphism:: sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-c : -b + c : 1/20*a + 1/20*b) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x) We verify that `f` maps the chosen point `P=(1,-1,0)` on the cubic to the origin of the elliptic curve:: sage: f([1,-1,0]) (0 : 1 : 0) sage: finv([0,1,0]) (-1 : 1 : 0) To verify the output, we plug in the polynomials to check that this indeed transforms the cubic into Weierstrass form:: sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + x^2*z + 2*x*y*z + y^2*z + 20*x*z^2 + 20*y*z^2 + 400/3*z^3 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + b^3 + 60*c^3 If the point is not a flex then the cubic can not be transformed to a Weierstrass equation by a linear transformation. The general birational transformation is quadratic:: sage: cubic = a^3+7*b^3+64*c^3 sage: P = [2,2,-1] sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: E = f.codomain(); E Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 To: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-5/112896*a^2 - 17/40320*a*b - 1/1280*b^2 - 29/35280*a*c - 13/5040*b*c - 4/2205*c^2 : -4055/112896*a^2 - 4787/40320*a*b - 91/1280*b^2 - 7769/35280*a*c - 1993/5040*b*c - 724/2205*c^2 : 1/4572288000*a^2 + 1/326592000*a*b + 1/93312000*b^2 + 1/142884000*a*c + 1/20412000*b*c + 1/17860500*c^2) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 Defn: Defined on coordinates by sending (x : y : z) to (2*x^2 + 227700*x*z - 900*y*z : 2*x^2 - 32940*x*z + 540*y*z : -x^2 - 56520*x*z - 180*y*z) sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 - 23579*x^2*z - 722*x*y*z + y^2*z - 21870000*y*z^2 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + 7*b^3 + 64*c^3 TESTS:: sage: R.<x,y,z> = QQ[] sage: cubic = x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 sage: EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=False) Elliptic Curve defined by y^2 - 882*x*y - 2560000*y = x^3 - 127281*x^2 over Rational Field """ import sage.matrix.all as matrix # check the input R = F.parent() if not is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('equation must be a polynomial in three variables') if not F.is_homogeneous(): raise TypeError('equation must be a homogeneous polynomial') K = F.parent().base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot convert %s into %s'%(P,K)) if F(P) != 0: raise ValueError('%s is not a point on %s'%(P,F)) if len(P) != 3: raise TypeError('%s is not a projective point'%P) x, y, z = R.gens() # First case: if P = P2 then P is a flex P2 = chord_and_tangent(F, P) if are_projectively_equivalent(P, P2, base_ring=K): # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # find a second point Q on the tangent line but not on the cubic for tangent in [[dy, -dx, K.zero()], [dz, K.zero(), -dx], [K.zero(), -dz, dx]]: tangent = projective_point(tangent) Q = [tangent[0]+P[0], tangent[1]+P[1], tangent[2]+P[2]] F_Q = F(Q) if F_Q != 0: # At most one further point may accidentally be on the cubic break assert F_Q != 0 # pick linearly independent third point for third_point in [(1,0,0), (0,1,0), (0,0,1)]: M = matrix.matrix(K, [Q, P, third_point]).transpose() if M.is_invertible(): break F2 = R(M.act_on_polynomial(F)) # scale and dehomogenise a = K(F2.coefficient(x**3)) F3 = F2/a b = K(F3.coefficient(y*y*z)) S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1/b)*S.gen(2) F4 = F3(X, Y, Z) E = EllipticCurve(F4.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i,0]*X + M[i,1]*Y + M[i,2]*Z for i in range(3) ] inv_post = -1/a M = M.inverse() trans_x, trans_y, trans_z = [ M[i,0]*x + M[i,1]*y + M[i,2]*z for i in range(3) ] fwd_defining_poly = [trans_x, trans_y, -b*trans_z] fwd_post = -a # Second case: P is not a flex, then P, P2, P3 are different else: P3 = chord_and_tangent(F, P2) # send P, P2, P3 to (1:0:0), (0:1:0), (0:0:1) respectively M = matrix.matrix(K, [P, P2, P3]).transpose() F2 = M.act_on_polynomial(F) # substitute x = U^2, y = V*W, z = U*W, and rename (x,y,z)=(U,V,W) F3 = F2.substitute({x:x**2, y:y*z, z:x*z}) // (x**2*z) # scale and dehomogenise a = K(F3.coefficient(x**3)) F4 = F3/a b = K(F4.coefficient(y*y*z)) # change to a polynomial in only two variables S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1/b)*S.gen(2) F5 = F4(X, Y, Z) E = EllipticCurve(F5.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i,0]*X*X + M[i,1]*Y*Z + M[i,2]*X*Z for i in range(3) ] inv_post = -1/a/(X**2)/Z M = M.inverse() trans_x, trans_y, trans_z = [ (M[i,0]*x + M[i,1]*y + M[i,2]*z) for i in range(3) ] fwd_defining_poly = [ trans_x*trans_z, trans_x*trans_y, -b*trans_z*trans_z ] fwd_post = -a/(trans_x*trans_z*trans_z) # Construct the morphism from sage.schemes.projective.projective_space import ProjectiveSpace P2 = ProjectiveSpace(2, K, names=map(str, R.gens())) cubic = P2.subscheme(F) from sage.schemes.elliptic_curves.weierstrass_transform import \ WeierstrassTransformationWithInverse return WeierstrassTransformationWithInverse( cubic, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post)
def chord_and_tangent(F, P): """ Use the chord and tangent method to get another point on a cubic. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. OUTPUT: Another point satisfying the equation ``F``. EXAMPLES:: sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent sage: F = x^3+y^3+60*z^3 sage: chord_and_tangent(F, [1,-1,0]) [1, -1, 0] sage: F = x^3+7*y^3+64*z^3 sage: p0 = [2,2,-1] sage: p1 = chord_and_tangent(F, p0); p1 [-5, 3, -1] sage: p2 = chord_and_tangent(F, p1); p2 [1265, -183, -314] TESTS:: sage: F(p2) 0 sage: list(map(type, p2)) [<type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>] See :trac:`16068`:: sage: F = x**3 - 4*x**2*y - 65*x*y**2 + 3*x*y*z - 76*y*z**2 sage: chord_and_tangent(F, [0, 1, 0]) [0, 0, -1] """ # check the input R = F.parent() if not is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('%s is not a polynomial in three variables' % F) if not F.is_homogeneous(): raise TypeError('%s is not a homogeneous polynomial' % F) x, y, z = R.gens() if len(P) != 3: raise TypeError('%s is not a projective point' % P) K = R.base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot coerce %s into %s' % (P, K)) if F(P) != 0: raise ValueError('%s is not a point on %s' % (P, F)) # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # if dF/dy(P) = 0, change variables so that dF/dy != 0 if dy == 0: if dx != 0: g = F.substitute({x: y, y: x}) Q = [P[1], P[0], P[2]] R = chord_and_tangent(g, Q) return [R[1], R[0], R[2]] elif dz != 0: g = F.substitute({y: z, z: y}) Q = [P[0], P[2], P[1]] R = chord_and_tangent(g, Q) return [R[0], R[2], R[1]] else: raise ValueError('%s is singular at %s' % (F, P)) # t will be our choice of parmeter of the tangent plane # dx*(x-P[0]) + dy*(y-P[1]) + dz*(z-P[2]) # through the point P t = rings.PolynomialRing(K, 't').gen(0) Ft = F(dy * t + P[0], -dx * t + P[1], P[2]) if Ft == 0: # (dy, -dx, 0) is projectively equivalent to P # then (0, -dz, dy) is not projectively equivalent to P g = F.substitute({x: z, z: x}) Q = [P[2], P[1], P[0]] R = chord_and_tangent(g, Q) return [R[2], R[1], R[0]] # Ft has a double zero at t=0 by construction, which we now remove Ft = Ft // t**2 # first case: the third point is at t=infinity if Ft.is_constant(): return projective_point([dy, -dx, K(0)]) # second case: the third point is at finite t else: assert Ft.degree() == 1 t0 = Ft.roots()[0][0] return projective_point([dy * t0 + P[0], -dx * t0 + P[1], P[2]])
def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False): """ A mutable list of elements with a common guaranteed universe, which can be set immutable. A universe is either an object that supports coercion (e.g., a parent), or a category. INPUT: - ``x`` - a list or tuple instance - ``universe`` - (default: None) the universe of elements; if None determined using canonical coercions and the entire list of elements. If list is empty, is category Objects() of all objects. - ``check`` -- (default: True) whether to coerce the elements of x into the universe - ``immutable`` - (default: True) whether or not this sequence is immutable - ``cr`` - (default: False) if True, then print a carriage return after each comma when printing this sequence. - ``cr_str`` - (default: False) if True, then print a carriage return after each comma when calling ``str()`` on this sequence. - ``use_sage_types`` -- (default: False) if True, coerce the built-in Python numerical types int, float, complex to the corresponding Sage types (this makes functions like vector() more flexible) OUTPUT: - a sequence EXAMPLES:: sage: v = Sequence(range(10)) sage: v.universe() <type 'int'> sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] We can request that the built-in Python numerical types be coerced to Sage objects:: sage: v = Sequence(range(10), use_sage_types=True) sage: v.universe() Integer Ring sage: v [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] You can also use seq for "Sequence", which is identical to using Sequence:: sage: v = seq([1,2,1/1]); v [1, 2, 1] sage: v.universe() Rational Field Note that assignment coerces if possible,:: sage: v = Sequence(range(10), ZZ) sage: a = QQ(5) sage: v[3] = a sage: parent(v[3]) Integer Ring sage: parent(a) Rational Field sage: v[3] = 2/3 Traceback (most recent call last): ... TypeError: no conversion of this rational to integer Sequences can be used absolutely anywhere lists or tuples can be used:: sage: isinstance(v, list) True Sequence can be immutable, so entries can't be changed:: sage: v = Sequence([1,2,3], immutable=True) sage: v.is_immutable() True sage: v[0] = 5 Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead. Only immutable sequences are hashable (unlike Python lists), though the hashing is potentially slow, since it first involves conversion of the sequence to a tuple, and returning the hash of that.:: sage: v = Sequence(range(10), ZZ, immutable=True) sage: hash(v) == hash(tuple(range(10))) True If you really know what you are doing, you can circumvent the type checking (for an efficiency gain):: sage: list.__setitem__(v, int(1), 2/3) # bad circumvention sage: v [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9] sage: list.__setitem__(v, int(1), int(2)) # not so bad circumvention You can make a sequence with a new universe from an old sequence.:: sage: w = Sequence(v, QQ) sage: w [0, 2, 2, 3, 4, 5, 6, 7, 8, 9] sage: w.universe() Rational Field sage: w[1] = 2/3 sage: w [0, 2/3, 2, 3, 4, 5, 6, 7, 8, 9] The default universe for any sequence, if no compatible parent structure can be found, is the universe of all Sage objects. This example illustrates how every element of a list is taken into account when constructing a sequence.:: sage: v = Sequence([1,7,6,GF(5)(3)]); v [1, 2, 1, 3] sage: v.universe() Finite Field of size 5 TESTS:: sage: Sequence(["a"], universe=ZZ) Traceback (most recent call last): ... TypeError: unable to convert a to an element of Integer Ring """ from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal if isinstance(x, Sequence_generic) and universe is None: universe = x.universe() x = list(x) if isinstance(x, MPolynomialIdeal) and universe is None: universe = x.ring() x = x.gens() if universe is None: orig_x = x x = list( x) # make a copy even if x is a list, we're going to change it if len(x) == 0: from sage.categories.objects import Objects universe = Objects() else: import sage.structure.element if use_sage_types: # convert any Python built-in numerical types to Sage objects x = [sage.structure.coerce.py_scalar_to_element(e) for e in x] # start the pairwise coercion for i in range(len(x) - 1): try: x[i], x[i + 1] = sage.structure.element.canonical_coercion( x[i], x[i + 1]) except TypeError: from sage.categories.objects import Objects universe = Objects() x = list(orig_x) check = False # no point break if universe is None: # no type errors raised. universe = sage.structure.element.parent(x[len(x) - 1]) from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.quotient_ring import is_QuotientRing if is_MPolynomialRing(universe) or isinstance( universe, BooleanMonomialMonoid) or (is_QuotientRing(universe) and is_MPolynomialRing( universe.cover_ring())): return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) else: return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types)
def AffineSpace(n, R=None, names=None, ambient_projective_space=None, default_embedding_index=None): r""" Return affine space of dimension ``n`` over the ring ``R``. EXAMPLES: The dimension and ring can be given in either order:: sage: AffineSpace(3, QQ, 'x') Affine Space of dimension 3 over Rational Field sage: AffineSpace(5, QQ, 'x') Affine Space of dimension 5 over Rational Field sage: A = AffineSpace(2, QQ, names='XY'); A Affine Space of dimension 2 over Rational Field sage: A.coordinate_ring() Multivariate Polynomial Ring in X, Y over Rational Field Use the divide operator for base extension:: sage: AffineSpace(5, names='x')/GF(17) Affine Space of dimension 5 over Finite Field of size 17 The default base ring is `\ZZ`:: sage: AffineSpace(5, names='x') Affine Space of dimension 5 over Integer Ring There is also an affine space associated to each polynomial ring:: sage: R = GF(7)['x, y, z'] sage: A = AffineSpace(R); A Affine Space of dimension 3 over Finite Field of size 7 sage: A.coordinate_ring() is R True TESTS:: sage: R.<w> = QQ[] sage: A.<w> = AffineSpace(R) sage: A.gens() == R.gens() True :: sage: R.<x> = QQ[] sage: A.<z> = AffineSpace(R) Traceback (most recent call last): ... NameError: variable names passed to AffineSpace conflict with names in ring """ if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None: R = n if names is not None: # Check for the case that the user provided a variable name # That does not match what we wanted to use from R names = normalize_names(R.ngens(), names) if n.variable_names() != names: # The provided name doesn't match the name of R's variables raise NameError("variable names passed to AffineSpace conflict with names in ring") A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names()) A._coordinate_ring = R return A if names is None: if n == 0: names = '' else: names = 'x' if isinstance(R, integer_types + (Integer,)): n, R = R, n if R is None: R = ZZ # default is the integers names = normalize_names(n, names) if default_embedding_index is not None and ambient_projective_space is None: from sage.schemes.projective.projective_space import ProjectiveSpace ambient_projective_space = ProjectiveSpace(n, R) if R in _Fields: if is_FiniteField(R): return AffineSpace_finite_field(n, R, names, ambient_projective_space, default_embedding_index) else: return AffineSpace_field(n, R, names, ambient_projective_space, default_embedding_index) return AffineSpace_generic(n, R, names, ambient_projective_space, default_embedding_index)
def EllipticCurve_from_cubic(F, P, morphism=True): r""" Construct an elliptic curve from a ternary cubic with a rational point. If you just want the Weierstrass form and are not interested in the morphism then it is easier to use :func:`~sage.schemes.elliptic_curves.jacobian.Jacobian` instead. This will construct the same elliptic curve but you don't have to supply the point ``P``. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. Need not be a flex, but see caveat on output. - ``morphism`` -- boolean (default: ``True``). Whether to return the morphism or just the elliptic curve. OUTPUT: An elliptic curve in long Weierstrass form isomorphic to the curve `F=0`. If ``morphism=True`` is passed, then a birational equivalence between F and the Weierstrass curve is returned. If the point happens to be a flex, then this is an isomorphism. EXAMPLES: First we find that the Fermat cubic is isomorphic to the curve with Cremona label 27a1:: sage: R.<x,y,z> = QQ[] sage: cubic = x^3+y^3+z^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 1/3*y = x^3 - x^2 - 1/3*x - 1/27 over Rational Field sage: E.cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label() '27a1' Next we find the minimal model and conductor of the Jacobian of the Selmer curve:: sage: R.<a,b,c> = QQ[] sage: cubic = a^3+b^3+60*c^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: E.conductor() 24300 We can also get the birational equivalence to and from the Weierstrass form. We start with an example where ``P`` is a flex and the equivalence is an isomorphism:: sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-c : -b + c : 1/20*a + 1/20*b) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x) We verify that `f` maps the chosen point `P=(1,-1,0)` on the cubic to the origin of the elliptic curve:: sage: f([1,-1,0]) (0 : 1 : 0) sage: finv([0,1,0]) (-1 : 1 : 0) To verify the output, we plug in the polynomials to check that this indeed transforms the cubic into Weierstrass form:: sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + x^2*z + 2*x*y*z + y^2*z + 20*x*z^2 + 20*y*z^2 + 400/3*z^3 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + b^3 + 60*c^3 If the point is not a flex then the cubic can not be transformed to a Weierstrass equation by a linear transformation. The general birational transformation is quadratic:: sage: cubic = a^3+7*b^3+64*c^3 sage: P = [2,2,-1] sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: E = f.codomain(); E Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 To: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-5/112896*a^2 - 17/40320*a*b - 1/1280*b^2 - 29/35280*a*c - 13/5040*b*c - 4/2205*c^2 : -4055/112896*a^2 - 4787/40320*a*b - 91/1280*b^2 - 7769/35280*a*c - 1993/5040*b*c - 724/2205*c^2 : 1/4572288000*a^2 + 1/326592000*a*b + 1/93312000*b^2 + 1/142884000*a*c + 1/20412000*b*c + 1/17860500*c^2) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 Defn: Defined on coordinates by sending (x : y : z) to (2*x^2 + 227700*x*z - 900*y*z : 2*x^2 - 32940*x*z + 540*y*z : -x^2 - 56520*x*z - 180*y*z) sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 - 23579*x^2*z - 722*x*y*z + y^2*z - 21870000*y*z^2 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + 7*b^3 + 64*c^3 TESTS:: sage: R.<x,y,z> = QQ[] sage: cubic = x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 sage: EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=False) Elliptic Curve defined by y^2 - 882*x*y - 2560000*y = x^3 - 127281*x^2 over Rational Field """ import sage.matrix.all as matrix # check the input R = F.parent() if not is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('equation must be a polynomial in three variables') if not F.is_homogeneous(): raise TypeError('equation must be a homogeneous polynomial') K = F.parent().base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot convert %s into %s' % (P, K)) if F(P) != 0: raise ValueError('%s is not a point on %s' % (P, F)) if len(P) != 3: raise TypeError('%s is not a projective point' % P) x, y, z = R.gens() # First case: if P = P2 then P is a flex P2 = chord_and_tangent(F, P) if are_projectively_equivalent(P, P2, base_ring=K): # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # find a second point Q on the tangent line but not on the cubic for tangent in [[dy, -dx, K.zero()], [dz, K.zero(), -dx], [K.zero(), -dz, dx]]: tangent = projective_point(tangent) Q = [tangent[0] + P[0], tangent[1] + P[1], tangent[2] + P[2]] F_Q = F(Q) if F_Q != 0: # At most one further point may accidentally be on the cubic break assert F_Q != 0 # pick linearly independent third point for third_point in [(1, 0, 0), (0, 1, 0), (0, 0, 1)]: M = matrix.matrix(K, [Q, P, third_point]).transpose() if M.is_invertible(): break F2 = R(M.act_on_polynomial(F)) # scale and dehomogenise a = K(F2.coefficient(x**3)) F3 = F2 / a b = K(F3.coefficient(y * y * z)) S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1 / b) * S.gen(2) F4 = F3(X, Y, Z) E = EllipticCurve(F4.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i, 0] * X + M[i, 1] * Y + M[i, 2] * Z for i in range(3) ] inv_post = -1 / a M = M.inverse() trans_x, trans_y, trans_z = [ M[i, 0] * x + M[i, 1] * y + M[i, 2] * z for i in range(3) ] fwd_defining_poly = [trans_x, trans_y, -b * trans_z] fwd_post = -a # Second case: P is not a flex, then P, P2, P3 are different else: P3 = chord_and_tangent(F, P2) # send P, P2, P3 to (1:0:0), (0:1:0), (0:0:1) respectively M = matrix.matrix(K, [P, P2, P3]).transpose() F2 = M.act_on_polynomial(F) # substitute x = U^2, y = V*W, z = U*W, and rename (x,y,z)=(U,V,W) F3 = F2.substitute({x: x**2, y: y * z, z: x * z}) // (x**2 * z) # scale and dehomogenise a = K(F3.coefficient(x**3)) F4 = F3 / a b = K(F4.coefficient(y * y * z)) # change to a polynomial in only two variables S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1 / b) * S.gen(2) F5 = F4(X, Y, Z) E = EllipticCurve(F5.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i, 0] * X * X + M[i, 1] * Y * Z + M[i, 2] * X * Z for i in range(3) ] inv_post = -1 / a / (X**2) / Z M = M.inverse() trans_x, trans_y, trans_z = [(M[i, 0] * x + M[i, 1] * y + M[i, 2] * z) for i in range(3)] fwd_defining_poly = [ trans_x * trans_z, trans_x * trans_y, -b * trans_z * trans_z ] fwd_post = -a / (trans_x * trans_z * trans_z) # Construct the morphism from sage.schemes.projective.projective_space import ProjectiveSpace P2 = ProjectiveSpace(2, K, names=[str(_) for _ in R.gens()]) cubic = P2.subscheme(F) from sage.schemes.elliptic_curves.weierstrass_transform import \ WeierstrassTransformationWithInverse return WeierstrassTransformationWithInverse(cubic, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post)
def Conic(base_field, F=None, names=None, unique=True): r""" Return the plane projective conic curve defined by ``F`` over ``base_field``. The input form ``Conic(F, names=None)`` is also accepted, in which case the fraction field of the base ring of ``F`` is used as base field. INPUT: - ``base_field`` -- The base field of the conic. - ``names`` -- a list, tuple, or comma separated string of three variable names specifying the names of the coordinate functions of the ambient space `\Bold{P}^3`. If not specified or read off from ``F``, then this defaults to ``'x,y,z'``. - ``F`` -- a polynomial, list, matrix, ternary quadratic form, or list or tuple of 5 points in the plane. If ``F`` is a polynomial or quadratic form, then the output is the curve in the projective plane defined by ``F = 0``. If ``F`` is a polynomial, then it must be a polynomial of degree at most 2 in 2 variables, or a homogeneous polynomial in of degree 2 in 3 variables. If ``F`` is a matrix, then the output is the zero locus of `(x,y,z) F (x,y,z)^t`. If ``F`` is a list of coefficients, then it has length 3 or 6 and gives the coefficients of the monomials `x^2, y^2, z^2` or all 6 monomials `x^2, xy, xz, y^2, yz, z^2` in lexicographic order. If ``F`` is a list of 5 points in the plane, then the output is a conic through those points. - ``unique`` -- Used only if ``F`` is a list of points in the plane. If the conic through the points is not unique, then raise ``ValueError`` if and only if ``unique`` is True OUTPUT: A plane projective conic curve defined by ``F`` over a field. EXAMPLES: Conic curves given by polynomials :: sage: X,Y,Z = QQ['X,Y,Z'].gens() sage: Conic(X^2 - X*Y + Y^2 - Z^2) Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2 sage: x,y = GF(7)['x,y'].gens() sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W') Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2 Conic curves given by matrices :: sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z') Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2 sage: x,y,z = GF(11)['x,y,z'].gens() sage: C = Conic(x^2+y^2-2*z^2); C Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 sage: Conic(C.symmetric_matrix(), 'x,y,z') Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 Conics given by coefficients :: sage: Conic(QQ, [1,2,3]) Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2 sage: Conic(GF(7), [1,2,3,4,5,6], 'X') Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2 The conic through a set of points :: sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2 sage: C.rational_point() (10 : 2 : 1) sage: C.point([3,4]) (3 : 4 : 1) sage: a=AffineSpace(GF(13),2) sage: Conic([a([x,x^2]) for x in range(5)]) Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z """ if not (base_field is None or isinstance(base_field, IntegralDomain)): if names is None: names = F F = base_field base_field = None if isinstance(F, (list, tuple)): if len(F) == 1: return Conic(base_field, F[0], names) if names is None: names = 'x,y,z' if len(F) == 5: L = [] for f in F: if isinstance(f, SchemeMorphism_point_affine): C = Sequence(f, universe=base_field) if len(C) != 2: raise TypeError("points in F (=%s) must be planar" % F) C.append(1) elif isinstance(f, SchemeMorphism_point_projective_field): C = Sequence(f, universe=base_field) elif isinstance(f, (list, tuple)): C = Sequence(f, universe=base_field) if len(C) == 2: C.append(1) else: raise TypeError("F (=%s) must be a sequence of planar " \ "points" % F) if len(C) != 3: raise TypeError("points in F (=%s) must be planar" % F) P = C.universe() if not isinstance(P, IntegralDomain): raise TypeError("coordinates of points in F (=%s) must " \ "be in an integral domain" % F) L.append( Sequence([ C[0]**2, C[0] * C[1], C[0] * C[2], C[1]**2, C[1] * C[2], C[2]**2 ], P.fraction_field())) M = Matrix(L) if unique and M.rank() != 5: raise ValueError("points in F (=%s) do not define a unique " \ "conic" % F) con = Conic(base_field, Sequence(M.right_kernel().gen()), names) con.point(F[0]) return con F = Sequence(F, universe=base_field) base_field = F.universe().fraction_field() temp_ring = PolynomialRing(base_field, 3, names) (x, y, z) = temp_ring.gens() if len(F) == 3: return Conic(F[0] * x**2 + F[1] * y**2 + F[2] * z**2) if len(F) == 6: return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \ F[4]*y*z + F[5]*z**2) raise TypeError("F (=%s) must be a sequence of 3 or 6" \ "coefficients" % F) if is_QuadraticForm(F): F = F.matrix() if is_Matrix(F) and F.is_square() and F.ncols() == 3: if names is None: names = 'x,y,z' temp_ring = PolynomialRing(F.base_ring(), 3, names) F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) if not is_MPolynomial(F): raise TypeError("F (=%s) must be a three-variable polynomial or " \ "a sequence of points or coefficients" % F) if F.total_degree() != 2: raise TypeError("F (=%s) must have degree 2" % F) if base_field is None: base_field = F.base_ring() if not isinstance(base_field, IntegralDomain): raise ValueError("Base field (=%s) must be a field" % base_field) base_field = base_field.fraction_field() if names is None: names = F.parent().variable_names() pol_ring = PolynomialRing(base_field, 3, names) if F.parent().ngens() == 2: (x, y, z) = pol_ring.gens() F = pol_ring(F(x / z, y / z) * z**2) if F == 0: raise ValueError("F must be nonzero over base field %s" % base_field) if F.total_degree() != 2: raise TypeError("F (=%s) must have degree 2 over base field %s" % \ (F, base_field)) if F.parent().ngens() == 3: P2 = ProjectiveSpace(2, base_field, names) if is_PrimeFiniteField(base_field): return ProjectiveConic_prime_finite_field(P2, F) if is_FiniteField(base_field): return ProjectiveConic_finite_field(P2, F) if is_RationalField(base_field): return ProjectiveConic_rational_field(P2, F) if is_NumberField(base_field): return ProjectiveConic_number_field(P2, F) if is_FractionField(base_field) and (is_PolynomialRing( base_field.ring()) or is_MPolynomialRing(base_field.ring())): return ProjectiveConic_rational_function_field(P2, F) return ProjectiveConic_field(P2, F) raise TypeError("Number of variables of F (=%s) must be 2 or 3" % F)
def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): """ Construct a new polynomial sequence object. INPUT: - ``arg1`` - a multivariate polynomial ring, an ideal or a matrix - ``arg2`` - an iterable object of parts or polynomials (default:``None``) - ``immutable`` - if ``True`` the sequence is immutable (default: ``False``) - ``cr`` - print a line break after each element (default: ``False``) - ``cr_str`` - print a line break after each element if 'str' is called (default: ``None``) EXAMPLES:: sage: P.<a,b,c,d> = PolynomialRing(GF(127),4) sage: I = sage.rings.ideal.Katsura(P) If a list of tuples is provided, those form the parts:: sage: F = Sequence([I.gens(),I.gens()], I.ring()); F # indirect doctest [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c, a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] sage: F.nparts() 2 If an ideal is provided, the generators are used:: sage: Sequence(I) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] If a list of polynomials is provided, the system has only one part:: sage: F = Sequence(I.gens(), I.ring()); F [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] sage: F.nparts() 1 """ from sage.matrix.matrix import is_Matrix if is_MPolynomialRing(arg1) or is_QuotientRing(arg1): ring = arg1 gens = arg2 elif is_MPolynomialRing(arg2) or is_QuotientRing(arg2): ring = arg2 gens = arg1 elif is_Matrix(arg1) and arg2 is None: ring = arg1.base_ring() gens = arg1.list() elif isinstance(arg1, MPolynomialIdeal) and arg2 is None: ring = arg1.ring() gens = arg1.gens() elif isinstance(arg1, (list,tuple,GeneratorType)) and arg2 is None: gens = arg1 try: e = iter(gens).next() except StopIteration: raise ValueError("Cannot determine ring from provided information.") if is_MPolynomial(e) or isinstance(e, QuotientRingElement): ring = e.parent() else: ring = iter(e).next().parent() else: raise TypeError("Cannot understand input.") try: e = iter(gens).next() if is_MPolynomial(e) or isinstance(e, QuotientRingElement): gens = tuple(gens) parts = (gens,) if not all(f.parent() is ring for f in gens): parts = ((ring(f) for f in gens),) else: parts = [] _gens = [] for part in gens: _part = [] for gen in part: if not gen.parent() is ring: ring(gen) _part.append(gen) _gens.extend(_part) parts.append(tuple(_part)) gens = _gens except StopIteration: gens = tuple() parts = ((),) k = ring.base_ring() try: c = k.characteristic() except NotImplementedError: c = -1 if c != 2: return PolynomialSequence_generic(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str) elif k.degree() == 1: return PolynomialSequence_gf2(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str) elif k.degree() > 1: return PolynomialSequence_gf2e(parts, ring, immutable=immutable, cr=cr, cr_str=cr_str)
def _coerce_map_from_(self, P): """ The rings that canonically coerce to this multivariate power series ring are: - this ring itself - a polynomial or power series ring in the same variables or a subset of these variables (possibly empty), over any base ring that canonically coerces into this ring - any ring that coerces into the foreground polynomial ring of this ring EXAMPLES:: sage: A = GF(17)[['x','y']] sage: A.has_coerce_map_from(ZZ) True sage: A.has_coerce_map_from(ZZ['x']) True sage: A.has_coerce_map_from(ZZ['y','x']) True sage: A.has_coerce_map_from(ZZ[['x']]) True sage: A.has_coerce_map_from(ZZ[['y','x']]) True sage: A.has_coerce_map_from(ZZ['x','z']) False sage: A.has_coerce_map_from(GF(3)['x','y']) False sage: A.has_coerce_map_from(Frac(ZZ['y','x'])) False TESTS:: sage: M = PowerSeriesRing(ZZ,3,'x,y,z'); sage: M._coerce_map_from_(M) True sage: M._coerce_map_from_(M.remove_var(x)) True sage: M._coerce_map_from_(PowerSeriesRing(ZZ,x)) True sage: M._coerce_map_from_(PolynomialRing(ZZ,'x,z')) True sage: M._coerce_map_from_(PolynomialRing(ZZ,0,'')) True sage: M._coerce_map_from_(ZZ) True sage: M._coerce_map_from_(Zmod(13)) False sage: M._coerce_map_from_(PolynomialRing(ZZ,2,'x,t')) False sage: M._coerce_map_from_(PolynomialRing(Zmod(11),2,'x,y')) False sage: P = PolynomialRing(ZZ,3,'z') sage: H = PowerSeriesRing(P,4,'f'); H Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring sage: H._coerce_map_from_(P) True sage: H._coerce_map_from_(P.remove_var(P.gen(1))) True sage: H._coerce_map_from_(PolynomialRing(ZZ,'z2,f0')) True """ if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \ or is_PolynomialRing(P) or is_PowerSeriesRing(P): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return True return self._poly_ring().has_coerce_map_from(P)