From f775a0ffaa6a969b5c3c4dc7a03862f0e71fdc58 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Sun, 19 Jun 2016 17:15:57 -0400 Subject: [PATCH 1/5] 20839: first implementation attempt. - intersection multiplicity for affine/projective curves - is_complete_intersection for projective curves - check whether two curves intersect at a point - compute intersection points of two curves --- src/sage/schemes/curves/affine_curve.py | 78 +++++++++++++ src/sage/schemes/curves/curve.py | 118 +++++++++++++++++++- src/sage/schemes/curves/projective_curve.py | 79 +++++++++++++ 3 files changed, 274 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index b797fe181b5..8ef1a89a7ba 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -142,6 +142,84 @@ def projective_closure(self, i=0, PP=None): from constructor import Curve return Curve(AlgebraicScheme_subscheme_affine.projective_closure(self, i, PP)) + def intersection_multiplicity(self, C, P): + r""" + Return the intersection multiplicity of this curve and the curve ``C`` at the point ``P``. + + INPUT: + + - ``C`` -- curve in the ambient space of this curve. + + - ``P`` -- a point in the intersection of this curve with ``C``. + + OUTPUT: + + An integer. + + EXAMPLES:: + + sage: A. = AffineSpace(QQ, 2) + sage: C = Curve([y^2 - x^3 - x^2], A) + sage: D = Curve([y^2 + x^3], A) + sage: Q = A([0,0]) + sage: C.intersection_multiplicity(D, Q) + 4 + + :: + + sage: A. = AffineSpace(QQ,3) + sage: C = Curve([y^2 + x + z, y^2 - z^2 + x], A) + sage: D = Curve([y + z^3 - z^2 + x, y^3 + x + z^3], A) + sage: Q1 = A([-1,1,0]) + sage: C.intersection_multiplicity(D, Q1) + 1 + sage: Q2 = A([1,1,1]) + sage: C.intersection_multiplicity(D, Q2) + Traceback (most recent call last): + ... + TypeError: (=(1, 1, 1)) must be a point in the intersection of this + curve with (=Affine Curve over Rational Field defined by z^3 - z^2 + x + + y, y^3 + z^3 + x) + + :: + + sage: A. = AffineSpace(GF(7), 2) + sage: C = Curve([y^3 - x^3], A) + sage: D = Curve([-x*y^3 + y^4 - 2*x^3 + 2*x^2*y], A) + sage: Q1 = A([-2,3]) + sage: C.intersection_multiplicity(D,Q1) + 1 + sage: Q2 = A([1,1]) + sage: C.intersection_multiplicity(D,Q2) + Traceback (most recent call last): + ... + TypeError: irreducible components of the intersection of this curve and + (=Affine Plane Curve over Finite Field of size 7 defined by -x^3 + y^3) + containing (=(1, 1)) must have dimension zero + """ + if not self.intersects_at(C, P): + raise TypeError("(=%s) must be a point in the intersection of this curve with (=%s)"%(P, C)) + T = self.intersection(C).irreducible_components() + for Y in T: + tmp = None + try: + tmp = Y(P) + except TypeError: + pass + if not tmp is None: + if Y.dimension() > 0: + raise TypeError("irreducible components of the intersection of this curve and (=%s) " \ + "containing (=%s) must have dimension zero"%(self,P)) + AA = self.ambient_space() + # polynomials defining intersection + polys = list(self.defining_polynomials()) + polys.extend(list(C.defining_polynomials())) + # move P to the origin + chng_coords = [AA.gens()[i] + P[i] for i in range(AA.dimension_relative())] + R = AA.coordinate_ring().change_ring(order="negdegrevlex") + I = R.ideal([f(chng_coords) for f in polys]) + return singular.vdim(singular.std(I)).sage() + class AffinePlaneCurve(AffineCurve): def __init__(self, A, f): r""" diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 86bac884298..8a8bb0d5d81 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -2,8 +2,9 @@ Generic curves. """ -from sage.misc.all import latex +from sage.categories.finite_fields import FiniteFields +from sage.misc.all import latex from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme @@ -195,3 +196,118 @@ def union(self, other): return Curve(AlgebraicScheme_subscheme.union(self, other)) __add__ = union + + def intersects_at(self, C, P): + r""" + Return whether the point ``P`` is or is not in the intersection of this curve with the curve ``C``. + + INPUT: + + - ``C`` -- a curve in the same ambient space as this curve. + + - ``P`` -- a point in the ambient space of this curve. + + OUTPUT: + + Boolean. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 3) + sage: C = Curve([x^2 - z^2, y^3 - w*x^2], P) + sage: D = Curve([w^2 - 2*x*y + z^2, y^2 - w^2], P) + sage: Q1 = P([1,1,-1,1]) + sage: C.intersects_at(D, Q1) + True + sage: Q2 = P([0,0,1,-1]) + sage: C.intersects_at(D, Q2) + False + + :: + + sage: A. = AffineSpace(GF(13), 2) + sage: C = Curve([y + 12*x^5 + 3*x^3 + 7], A) + sage: D = Curve([y^2 + 7*x^2 + 8], A) + sage: Q1 = A([9,6]) + sage: C.intersects_at(D, Q1) + True + sage: Q2 = A([3,7]) + sage: C.intersects_at(D, Q2) + False + """ + if C.ambient_space() != self.ambient_space(): + raise TypeError("(=%s) must be a curve in the same ambient space as (=%s)"%(C,self)) + if not isinstance(C, Curve_generic): + raise TypeError("(=%s) must be a curve"%C) + try: + P = self.ambient_space()(P) + except TypeError: + raise TypeError("(=%s) must be a point in the ambient space of this curve"%P) + try: + P = self(P) + except TypeError: + return False + try: + P = C(P) + except TypeError: + return False + return True + + def intersection_points(self, C, F=None): + r""" + Return the points in the intersection of this curve and the curve ``C``. + + If the intersection of these two curves has dimension greater than zero, and if + the base ring of this curve is not a finite field, then an error is returned. + + INPUT: + + - ``C`` -- a curve in the same ambient space as this curve. + + - ``F`` -- (default: None). Field over which to compute the intersection points. If not specified, + the base ring of this curve is used. + + OUTPUT: + + - a list of points in the ambient space of this curve. + + EXAMPLES:: + + sage: R. = QQ[] + sage: K. = NumberField(a^2 + a + 1) + sage: P. = ProjectiveSpace(QQ, 3) + sage: C = Curve([y^2 - w*z, w^3 - y^3], P) + sage: D = Curve([x*y - w*z, z^3 - y^3], P) + sage: C.intersection_points(D, F=K) + [(-b - 1 : -b - 1 : b : 1), (b : b : -b - 1 : 1), (1 : 1 : 1 : 1)] + + :: + + sage: A. = AffineSpace(GF(7), 2) + sage: C = Curve([y^3 - x^3], A) + sage: D = Curve([-x*y^3 + y^4 - 2*x^3 + 2*x^2*y], A) + sage: C.intersection_points(D) + [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 3), (5, 5), (5, 6), (6, 6)] + + :: + + sage: A. = AffineSpace(QQ, 2) + sage: C = Curve([y^3 - x^3], A) + sage: D = Curve([-x*y^3 + y^4 - 2*x^3 + 2*x^2*y], A) + sage: C.intersection_points(D) + Traceback (most recent call last): + ... + NotImplementedError: the intersection must have dimension zero or + (=Rational Field) must be a finite field + """ + if C.ambient_space() != self.ambient_space(): + raise TypeError("(=%s) must be a curve in the same ambient space as (=%s)"%(C,self)) + if not isinstance(C, Curve_generic): + raise TypeError("(=%s) must be a curve"%C) + X = self.intersection(C) + if F is None: + F = self.base_ring() + if X.dimension() == 0 or F in FiniteFields(): + return X.rational_points(F=F) + else: + raise NotImplementedError("the intersection must have dimension zero or (=%s) must be a finite field"%F) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 2d64ba6fbe5..51d85cb973a 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -128,6 +128,85 @@ def affine_patch(self, i, AA=None): from constructor import Curve return Curve(AlgebraicScheme_subscheme_projective.affine_patch(self, i, AA)) + def is_complete_intersection(self): + r""" + Return whether this projective curve is or is not a complete intersection. + + OUTPUT: + + Boolean. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 3) + sage: C = Curve([y*w - x^2, z*w^2 - x^3], P) + sage: C.is_complete_intersection() + False + + :: + + sage: P. = ProjectiveSpace(QQ, 4) + sage: C = Curve([y - z - w, y^3 - x*w*u, u^2 - x^2 - y^2], P) + sage: C.is_complete_intersection() + True + """ + singular.lib("sing.lib") + I = singular.simplify(self.defining_ideal().radical(), 10) + L = singular.is_ci(I).sage() + return len(self.ambient_space().gens()) - len(I.sage().gens()) == L[-1] + + def intersection_multiplicity(self, C, P): + r""" + Return the intersection multiplicity of this curve and the curve ``C`` at the point ``P``. + + This is computed by computing the corresponding multiplicity of the intersection of affine patches + of this curve and ``C`` at ``P``. + + INPUT: + + - ``C`` -- curve in the ambient space of this curve. + + - ``P`` -- a point in the intersection of this curve with ``C``. + + OUTPUT: + + An integer. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 3) + sage: C = Curve([x^2 - z^2, y^3 - w*x^2], P) + sage: D = Curve([w^2 - 2*x*y + z^2, y^2 - w^2], P) + sage: Q = P([1,1,-1,1]) + sage: C.intersection_multiplicity(D, Q) + 1 + + :: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: C = Curve([x^4 - z^2*y^2], P) + sage: D = Curve([y^4*z - x^5 - x^3*z^2], P) + sage: Q1 = P([0,1,0]) + sage: C.intersection_multiplicity(D, Q1) + 4 + sage: Q2 = P([0,0,1]) + sage: C.intersection_multiplicity(D, Q2) + 6 + """ + if not self.intersects_at(C, P): + raise TypeError("(=%s) must be a point in the intersection of this curve with (=%s)"%(P, C)) + # Find an affine chart of the ambient space of this curve that contains P + n = self.ambient_space().dimension_relative() + for i in range(n + 1): + if P[i] != 0: + break + C1 = self.affine_patch(i) + C2 = C.affine_patch(i) + Q = list(P) + t = Q.pop(i) + Q = [1/t*Q[j] for j in range(n)] + return C1.intersection_multiplicity(C2, Q) + class ProjectivePlaneCurve(ProjectiveCurve): def __init__(self, A, f): r""" From e0188ce3e3283fd7d8234dfa115d6d7ec1fa3b87 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Tue, 21 Jun 2016 02:03:52 -0400 Subject: [PATCH 2/5] 20839: some changes from review --- src/sage/schemes/curves/affine_curve.py | 28 +++++++++++++-- src/sage/schemes/curves/curve.py | 3 -- src/sage/schemes/curves/projective_curve.py | 38 +++++++++++++++++---- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 8ef1a89a7ba..367e62d5257 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -152,9 +152,7 @@ def intersection_multiplicity(self, C, P): - ``P`` -- a point in the intersection of this curve with ``C``. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: @@ -426,6 +424,30 @@ def plot(self, *args, **kwds): I = self.defining_ideal() return I.plot(*args, **kwds) + def is_transverse(self, C, P): + r""" + Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse. + + INPUT: + + - ``C`` -- a curve in the ambient space of this curve. + + - ``P`` -- a point in the intersection of both curves that is not a singular point of either curve. + + OUPUT: Boolean. + + EXAMPLES:: + + + """ + if not self.intersects_at(C, P): + raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) + if self.is_singular(P) or C.is_singular(P): + raise TypeError("(=%s) must be a nonsingular point of both (=%s) and this curve"%(P,C)) + + # there is only one tangent at a nonsingular point of a plane curve + return not self.tangents(P)[0] == C.tangents(P)[0] + class AffinePlaneCurve_finite_field(AffinePlaneCurve): def rational_points(self, algorithm="enum"): r""" diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 8a8bb0d5d81..79fd5e699d7 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -245,9 +245,6 @@ def intersects_at(self, C, P): raise TypeError("(=%s) must be a point in the ambient space of this curve"%P) try: P = self(P) - except TypeError: - return False - try: P = C(P) except TypeError: return False diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 51d85cb973a..005a93e0559 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -132,9 +132,7 @@ def is_complete_intersection(self): r""" Return whether this projective curve is or is not a complete intersection. - OUTPUT: - - Boolean. + OUTPUT: Boolean. EXAMPLES:: @@ -149,9 +147,14 @@ def is_complete_intersection(self): sage: C = Curve([y - z - w, y^3 - x*w*u, u^2 - x^2 - y^2], P) sage: C.is_complete_intersection() True + + sage: P. = ProjectiveSpace(QQ, 3) + sage: X = Curve([x*z - y^2, z*(y*w - z^2) - w*(x*w - y*z)]) + sage: X.is_complete_intersection() + False """ singular.lib("sing.lib") - I = singular.simplify(self.defining_ideal().radical(), 10) + I = singular.simplify(self.defining_ideal(), 10) L = singular.is_ci(I).sage() return len(self.ambient_space().gens()) - len(I.sage().gens()) == L[-1] @@ -168,9 +171,7 @@ def intersection_multiplicity(self, C, P): - ``P`` -- a point in the intersection of this curve with ``C``. - OUTPUT: - - An integer. + OUTPUT: An integer. EXAMPLES:: @@ -511,6 +512,29 @@ def is_singular(C): poly = C.defining_polynomial() return poly.parent().ideal(poly.gradient()+[poly]).dimension()> 0 + def is_transverse(self, C, P): + r""" + Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse. + + INPUT: + + - ``C`` -- a curve in the ambient space of this curve. + + - ``P`` -- a point in the intersection of both curves that is not a singular point of either curve. + + OUPUT: Boolean. + + EXAMPLES:: + + + """ + if not self.intersects_at(C, P): + raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) + if self.is_singular(P) or C.is_singular(P): + raise TypeError("(=%s) must be a nonsingular point of both (=%s) and this curve"%(P,C)) + + # there is only one tangent at a nonsingular point of a plane curve + return not self.tangents(P)[0] == C.tangents(P)[0] class ProjectivePlaneCurve_finite_field(ProjectivePlaneCurve): def rational_points_iterator(self): From 09eea02208e31ac7a3d829fd307c01d133ed0c08 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Tue, 21 Jun 2016 03:58:04 -0400 Subject: [PATCH 3/5] 20839: some remaining changes from review --- src/sage/schemes/curves/affine_curve.py | 16 ++++++- src/sage/schemes/curves/curve.py | 2 +- src/sage/schemes/curves/projective_curve.py | 48 ++++++++++++++++++--- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 0a7b7dff59b..822aa7d48ff 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -507,7 +507,21 @@ def is_transverse(self, C, P): EXAMPLES:: - + sage: A. = AffineSpace(QQ, 2) + sage: C = Curve([x^2 + y^2 - 1], A) + sage: D = Curve([x - 1], A) + sage: Q = A([1,0]) + sage: C.is_transverse(D, Q) + False + + :: + + sage: A. = AffineSpace(QQ, 2) + sage: C = Curve([y - x^3], A) + sage: D = Curve([y + x], A) + sage: Q = A([0,0]) + sage: C.is_transverse(D, Q) + True """ if not self.intersects_at(C, P): raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 876676dfd3f..956bf9521c4 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -389,7 +389,7 @@ def intersection_points(self, C, F=None): sage: C = Curve([y^2 - w*z, w^3 - y^3], P) sage: D = Curve([x*y - w*z, z^3 - y^3], P) sage: C.intersection_points(D, F=K) - [(-b - 1 : -b - 1 : b : 1), (b : b : -b - 1 : 1), (1 : 1 : 1 : 1)] + [(-b - 1 : -b - 1 : b : 1), (b : b : -b - 1 : 1), (1 : 0 : 0 : 0), (1 : 1 : 1 : 1)] :: diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index a43b9d9102e..66122fb0c72 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -214,20 +214,20 @@ def is_complete_intersection(self): EXAMPLES:: sage: P. = ProjectiveSpace(QQ, 3) - sage: C = Curve([y*w - x^2, z*w^2 - x^3], P) + sage: C = Curve([x*y - z*w, x^2 - y*w, y^2*w - x*z*w], P) sage: C.is_complete_intersection() False :: - sage: P. = ProjectiveSpace(QQ, 4) - sage: C = Curve([y - z - w, y^3 - x*w*u, u^2 - x^2 - y^2], P) + sage: P. = ProjectiveSpace(QQ, 3) + sage: C = Curve([y*w - x^2, z*w^2 - x^3], P) sage: C.is_complete_intersection() True sage: P. = ProjectiveSpace(QQ, 3) - sage: X = Curve([x*z - y^2, z*(y*w - z^2) - w*(x*w - y*z)]) - sage: X.is_complete_intersection() + sage: C = Curve([z^2 - y*w, y*z - x*w, y^2 - x*z], P) + sage: C.is_complete_intersection() False """ singular.lib("sing.lib") @@ -728,6 +728,44 @@ def is_ordinary_singularity(self, P): # otherwise they are distinct return True + def is_transverse(self, C, P): + r""" + Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse. + + INPUT: + + - ``C`` -- a curve in the ambient space of this curve. + + - ``P`` -- a point in the intersection of both curves that is not a singular point of either curve. + + OUPUT: Boolean. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: C = Curve([x^2 - y^2], P) + sage: D = Curve([x - y], P) + sage: Q = P([1,1,0]) + sage: C.is_transverse(D, Q) + False + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: C = Curve([x^2 - 2*y^2 - 2*z^2], P) + sage: D = Curve([y - z], P) + sage: Q = P([2,1,1]) + sage: C.is_transverse(D, Q) + True + """ + if not self.intersects_at(C, P): + raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) + if self.is_singular(P) or C.is_singular(P): + raise TypeError("(=%s) must be a nonsingular point of both (=%s) and this curve"%(P,C)) + + # there is only one tangent at a nonsingular point of a plane curve + return not self.tangents(P)[0] == C.tangents(P)[0] + class ProjectivePlaneCurve_finite_field(ProjectivePlaneCurve): def rational_points_iterator(self): r""" From 4b9ab0a8d1744f35fa507ff46da2cf032d7405d7 Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Wed, 22 Jun 2016 19:19:03 -0400 Subject: [PATCH 4/5] 20839: implemented Serre intersection multiplicity for affine/projective subschemes --- src/sage/schemes/curves/affine_curve.py | 76 --------- src/sage/schemes/curves/projective_curve.py | 50 ------ src/sage/schemes/generic/algebraic_scheme.py | 161 +++++++++++++++++++ 3 files changed, 161 insertions(+), 126 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 822aa7d48ff..6564ce1ecc3 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -211,82 +211,6 @@ def multiplicity(self, P): I = R.ideal([f(chng_coords) for f in self.defining_polynomials()]) return singular.mult(singular.std(I)).sage() - def intersection_multiplicity(self, C, P): - r""" - Return the intersection multiplicity of this curve and the curve ``C`` at the point ``P``. - - INPUT: - - - ``C`` -- curve in the ambient space of this curve. - - - ``P`` -- a point in the intersection of this curve with ``C``. - - OUTPUT: An integer. - - EXAMPLES:: - - sage: A. = AffineSpace(QQ, 2) - sage: C = Curve([y^2 - x^3 - x^2], A) - sage: D = Curve([y^2 + x^3], A) - sage: Q = A([0,0]) - sage: C.intersection_multiplicity(D, Q) - 4 - - :: - - sage: A. = AffineSpace(QQ,3) - sage: C = Curve([y^2 + x + z, y^2 - z^2 + x], A) - sage: D = Curve([y + z^3 - z^2 + x, y^3 + x + z^3], A) - sage: Q1 = A([-1,1,0]) - sage: C.intersection_multiplicity(D, Q1) - 1 - sage: Q2 = A([1,1,1]) - sage: C.intersection_multiplicity(D, Q2) - Traceback (most recent call last): - ... - TypeError: (=(1, 1, 1)) must be a point in the intersection of this - curve with (=Affine Curve over Rational Field defined by z^3 - z^2 + x + - y, y^3 + z^3 + x) - - :: - - sage: A. = AffineSpace(GF(7), 2) - sage: C = Curve([y^3 - x^3], A) - sage: D = Curve([-x*y^3 + y^4 - 2*x^3 + 2*x^2*y], A) - sage: Q1 = A([-2,3]) - sage: C.intersection_multiplicity(D,Q1) - 1 - sage: Q2 = A([1,1]) - sage: C.intersection_multiplicity(D,Q2) - Traceback (most recent call last): - ... - TypeError: irreducible components of the intersection of this curve and - (=Affine Plane Curve over Finite Field of size 7 defined by -x^3 + y^3) - containing (=(1, 1)) must have dimension zero - """ - if not self.intersects_at(C, P): - raise TypeError("(=%s) must be a point in the intersection of this curve with (=%s)"%(P, C)) - T = self.intersection(C).irreducible_components() - for Y in T: - tmp = None - try: - tmp = Y(P) - except TypeError: - pass - if not tmp is None: - if Y.dimension() > 0: - raise TypeError("irreducible components of the intersection of this curve and (=%s) " \ - "containing (=%s) must have dimension zero"%(self,P)) - AA = self.ambient_space() - # polynomials defining intersection - polys = list(self.defining_polynomials()) - polys.extend(list(C.defining_polynomials())) - # move P to the origin - chng_coords = [AA.gens()[i] + P[i] for i in range(AA.dimension_relative())] - R = AA.coordinate_ring().change_ring(order="negdegrevlex") - I = R.ideal([f(chng_coords) for f in polys]) - return singular.vdim(singular.std(I)).sage() - class AffinePlaneCurve(AffineCurve): def __init__(self, A, f): r""" diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 66122fb0c72..4bef6d11e00 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -235,56 +235,6 @@ def is_complete_intersection(self): L = singular.is_ci(I).sage() return len(self.ambient_space().gens()) - len(I.sage().gens()) == L[-1] - def intersection_multiplicity(self, C, P): - r""" - Return the intersection multiplicity of this curve and the curve ``C`` at the point ``P``. - - This is computed by computing the corresponding multiplicity of the intersection of affine patches - of this curve and ``C`` at ``P``. - - INPUT: - - - ``C`` -- curve in the ambient space of this curve. - - - ``P`` -- a point in the intersection of this curve with ``C``. - - OUTPUT: An integer. - - EXAMPLES:: - - sage: P. = ProjectiveSpace(QQ, 3) - sage: C = Curve([x^2 - z^2, y^3 - w*x^2], P) - sage: D = Curve([w^2 - 2*x*y + z^2, y^2 - w^2], P) - sage: Q = P([1,1,-1,1]) - sage: C.intersection_multiplicity(D, Q) - 1 - - :: - - sage: P. = ProjectiveSpace(GF(5), 2) - sage: C = Curve([x^4 - z^2*y^2], P) - sage: D = Curve([y^4*z - x^5 - x^3*z^2], P) - sage: Q1 = P([0,1,0]) - sage: C.intersection_multiplicity(D, Q1) - 4 - sage: Q2 = P([0,0,1]) - sage: C.intersection_multiplicity(D, Q2) - 6 - """ - if not self.intersects_at(C, P): - raise TypeError("(=%s) must be a point in the intersection of this curve with (=%s)"%(P, C)) - # Find an affine chart of the ambient space of this curve that contains P - n = self.ambient_space().dimension_relative() - for i in range(n + 1): - if P[i] != 0: - break - C1 = self.affine_patch(i) - C2 = C.affine_patch(i) - Q = list(P) - t = Q.pop(i) - Q = [1/t*Q[j] for j in range(n)] - return C1.intersection_multiplicity(C2, Q) - class ProjectivePlaneCurve(ProjectiveCurve): def __init__(self, A, f): r""" diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 45f824addba..98e4e9d1179 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -133,6 +133,8 @@ from sage.categories.number_fields import NumberFields from sage.categories.morphism import Morphism +from sage.interfaces.all import singular + from sage.rings.all import ZZ from sage.rings.ideal import is_Ideal from sage.rings.rational_field import is_RationalField @@ -2020,6 +2022,96 @@ def is_smooth(self, point=None): self._smooth = (sing_dim == -1) return self._smooth + def intersection_multiplicity(self, X, P): + r""" + Return the intersection multiplicity of this subscheme and the subscheme ``X`` at the point ``P``. + + The intersection of this subscheme with ``X`` must be proper, that is `\mathrm{codim}(self\cap + X) = \mathrm{codim}(self) + \mathrm{codim}(X)`, and must also be finite. We use Serre's Tor + formula to compute the intersection multiplicity. If `I`, `J` are the defining ideals of ``self``, ``X``, + respectively, then this is `\sum_{i=0}^{\infty}(-1)^i\mathrm{length}(\mathrm{Tor}_{\mathcal{O}_{A,p}}^{i} + (\mathcal{O}_{A,p}/I,\mathcal{O}_{A,p}/J))` where `A` is the affine ambient space of these subschemes. + + INPUT: + + - ``X`` -- subscheme in the same ambient space as this subscheme. + + - ``P`` -- a point in the intersection of this subscheme with ``X``. + + OUTPUT: An integer. + + EXAMPLES:: + + sage: A. = AffineSpace(QQ, 2) + sage: C = Curve([y^2 - x^3 - x^2], A) + sage: D = Curve([y^2 + x^3], A) + sage: Q = A([0,0]) + sage: C.intersection_multiplicity(D, Q) + 4 + + :: + + sage: R. = QQ[] + sage: K. = NumberField(a^6 - 3*a^5 + 5*a^4 - 5*a^3 + 5*a^2 - 3*a + 1) + sage: A. = AffineSpace(K, 4) + sage: X = A.subscheme([x*y, y*z + 7, w^3 - x^3]) + sage: Y = A.subscheme([x - z^3 + z + 1]) + sage: Q = A([0, -7*b^5 + 21*b^4 - 28*b^3 + 21*b^2 - 21*b + 14, -b^5 + 2*b^4 - 3*b^3 \ + + 2*b^2 - 2*b, 0]) + sage: X.intersection_multiplicity(Y, Q) + 3 + + :: + + sage: A. = AffineSpace(QQ, 3) + sage: X = A.subscheme([z^2 - 1]) + sage: Y = A.subscheme([z - 1, y - x^2]) + sage: Q = A([1,1,1]) + sage: X.intersection_multiplicity(Y, Q) + Traceback (most recent call last): + ... + TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 3 + over Rational Field defined by: z - 1, -x^2 + y) must be proper and finite + + :: + + sage: A. = AffineSpace(QQ, 5) + sage: X = A.subscheme([x*y, t^2*w, w^3*z]) + sage: Y = A.subscheme([y*w + z]) + sage: Q = A([0,0,0,0,0]) + sage: X.intersection_multiplicity(Y, Q) + Traceback (most recent call last): + ... + TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 5 + over Rational Field defined by: y*w + z) must be proper and finite + """ + AA = self.ambient_space() + if AA != X.ambient_space(): + raise TypeError("this subscheme and (=%s) must be defined in the same ambient space"%X) + W = self.intersection(X) + try: + W._check_satisfies_equations(P) + except TypeError: + raise TypeError("(=%s) must be a point in the intersection of this subscheme and (=%s)"%(P,X)) + if AA.dimension() != self.dimension() + X.dimension() or W.dimension() != 0: + raise TypeError("the intersection of this subscheme and (=%s) must be proper and finite"%X) + I = self.defining_ideal() + J = X.defining_ideal() + # move P to the origin and localize + chng_coords = [AA.gens()[i] + P[i] for i in range(AA.dimension_relative())] + R = AA.coordinate_ring().change_ring(order="negdegrevlex") + Iloc = R.ideal([f(chng_coords) for f in I.gens()]) + Jloc = R.ideal([f(chng_coords) for f in J.gens()]) + # compute the intersection multiplicity with Serre's Tor formula using Singular + singular.lib("homolog.lib") + i = 0 + s = 0 + t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) + while t != 0: + s = s + ((-1)**i)*t + i = i + 1 + t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) + return s #******************************************************************* @@ -2958,6 +3050,75 @@ def dual(self): L = J_sat.elimination_ideal(z[0: n + 1] + (z[-1],)) return Pd.subscheme(L.change_ring(Rd)) + def intersection_multiplicity(self, X, P): + r""" + Return the intersection multiplicity of this subscheme and the subscheme ``X`` at the point ``P``. + + This uses the intersection_multiplicity function for affine subschemes on affine patches of this subscheme + and ``X`` that contain ``P``. + + INPUT: + + - ``X`` -- subscheme in the same ambient space as this subscheme. + + - ``P`` -- a point in the intersection of this subscheme with ``X``. + + OUTPUT: An integer. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: C = Curve([x^4 - z^2*y^2], P) + sage: D = Curve([y^4*z - x^5 - x^3*z^2], P) + sage: Q1 = P([0,1,0]) + sage: C.intersection_multiplicity(D, Q1) + 4 + sage: Q2 = P([0,0,1]) + sage: C.intersection_multiplicity(D, Q2) + 6 + + :: + + sage: R. = QQ[] + sage: K. = NumberField(a^4 + 1) + sage: P. = ProjectiveSpace(K, 3) + sage: X = P.subscheme([x^2 + y^2 - z*w]) + sage: Y = P.subscheme([y*z - x*w, z - w]) + sage: Q1 = P([b^2,1,0,0]) + sage: X.intersection_multiplicity(Y, Q1) + 1 + sage: Q2 = P([1/2*b^3-1/2*b,1/2*b^3-1/2*b,1,1]) + sage: X.intersection_multiplicity(Y, Q2) + 1 + + :: + + sage: P. = ProjectiveSpace(QQ, 3) + sage: X = P.subscheme([x^2 - z^2, y^3 - w*x^2]) + sage: Y = P.subscheme([w^2 - 2*x*y + z^2, y^2 - w^2]) + sage: Q = P([1,1,-1,1]) + sage: X.intersection_multiplicity(Y, Q) + Traceback (most recent call last): + ... + TypeError: the intersection of this subscheme and (=Closed subscheme of Affine Space of dimension 3 + over Rational Field defined by: x1^2 + x2^2 - 2*x0, x0^2 - x2^2) must be proper and finite + """ + try: + self.ambient_space()(P) + except TypeError: + raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)"%(P,X)) + # find an affine chart of the ambient space of this curve that contains P + n = self.ambient_space().dimension_relative() + for i in range(n + 1): + if P[i] != 0: + break + X1 = self.affine_patch(i) + X2 = X.affine_patch(i) + Q = list(P) + t = Q.pop(i) + Q = [1/t*Q[j] for j in range(n)] + return X1.intersection_multiplicity(X2, X1.ambient_space()(Q)) + class AlgebraicScheme_subscheme_product_projective(AlgebraicScheme_subscheme_projective): @cached_method From cae16fe73a6db14d63156e509c48b160ae17094e Mon Sep 17 00:00:00 2001 From: Grayson Jorgenson Date: Thu, 23 Jun 2016 22:52:41 -0400 Subject: [PATCH 5/5] 20839: improved is_transverse --- src/sage/schemes/curves/affine_curve.py | 18 ++++++++++++++++-- src/sage/schemes/curves/projective_curve.py | 17 +++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 6564ce1ecc3..a12e2b350e6 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -421,11 +421,14 @@ def is_transverse(self, C, P): r""" Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse. + The intersection at ``P`` is transverse if ``P`` is a nonsingular point of both curves, and if the + tangents of the curves at ``P`` are distinct. + INPUT: - ``C`` -- a curve in the ambient space of this curve. - - ``P`` -- a point in the intersection of both curves that is not a singular point of either curve. + - ``P`` -- a point in the intersection of both curves. OUPUT: Boolean. @@ -438,6 +441,17 @@ def is_transverse(self, C, P): sage: C.is_transverse(D, Q) False + :: + + sage: R. = QQ[] + sage: K. = NumberField(a^3 + 2) + sage: A. = AffineSpace(K, 2) + sage: C = A.curve([x*y]) + sage: D = A.curve([y - b*x]) + sage: Q = A([0,0]) + sage: C.is_transverse(D, Q) + False + :: sage: A. = AffineSpace(QQ, 2) @@ -450,7 +464,7 @@ def is_transverse(self, C, P): if not self.intersects_at(C, P): raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) if self.is_singular(P) or C.is_singular(P): - raise TypeError("(=%s) must be a nonsingular point of both (=%s) and this curve"%(P,C)) + return False # there is only one tangent at a nonsingular point of a plane curve return not self.tangents(P)[0] == C.tangents(P)[0] diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 4bef6d11e00..b968cbb5fe8 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -682,11 +682,14 @@ def is_transverse(self, C, P): r""" Return whether the intersection of this curve with the curve ``C`` at the point ``P`` is transverse. + The intersection at ``P`` is transverse if ``P`` is a nonsingular point of both curves, and if the + tangents of the curves at ``P`` are distinct. + INPUT: - ``C`` -- a curve in the ambient space of this curve. - - ``P`` -- a point in the intersection of both curves that is not a singular point of either curve. + - ``P`` -- a point in the intersection of both curves. OUPUT: Boolean. @@ -699,6 +702,16 @@ def is_transverse(self, C, P): sage: C.is_transverse(D, Q) False + :: + + sage: K = QuadraticField(-1) + sage: P. = ProjectiveSpace(K, 2) + sage: C = Curve([y^2*z - K.0*x^3], P) + sage: D = Curve([z*x + y^2], P) + sage: Q = P([0,0,1]) + sage: C.is_transverse(D, Q) + False + :: sage: P. = ProjectiveSpace(QQ, 2) @@ -711,7 +724,7 @@ def is_transverse(self, C, P): if not self.intersects_at(C, P): raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) if self.is_singular(P) or C.is_singular(P): - raise TypeError("(=%s) must be a nonsingular point of both (=%s) and this curve"%(P,C)) + return False # there is only one tangent at a nonsingular point of a plane curve return not self.tangents(P)[0] == C.tangents(P)[0]