Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
20839: merge with ticket 20774
Browse files Browse the repository at this point in the history
  • Loading branch information
gsjorgenson committed Jun 21, 2016
2 parents e0188ce + 4282a4f commit 6564724
Show file tree
Hide file tree
Showing 4 changed files with 573 additions and 18 deletions.
247 changes: 247 additions & 0 deletions src/sage/schemes/curves/affine_curve.py
Expand Up @@ -34,8 +34,10 @@
# http://www.gnu.org/licenses/
#*****************************************************************************

from sage.categories.fields import Fields
from sage.categories.homset import Hom
from sage.interfaces.all import singular
import sage.libs.singular

from sage.misc.all import add

Expand Down Expand Up @@ -142,6 +144,73 @@ def projective_closure(self, i=0, PP=None):
from constructor import Curve
return Curve(AlgebraicScheme_subscheme_affine.projective_closure(self, i, PP))

def multiplicity(self, P):
r"""
Return the multiplicity of this affine curve at the point ``P``.
This is computed as the multiplicity of the local ring of self corresponding to ``P``. This
curve must be defined over a field. An error is raised if ``P`` is not a point on this curve.
INPUT:
- ``P`` -- a point in the ambient space of this curve.
OUTPUT:
An integer.
EXAMPLES::
sage: A.<x,y,z> = AffineSpace(CC, 3)
sage: C = A.curve([y - x^2, z - x^3])
sage: Q = A([1,1,1])
sage: C.multiplicity(Q)
1
::
sage: A.<x,y,z,w> = AffineSpace(QQ, 4)
sage: C = A.curve([y^9 - x^5, z^10 - w - y^4, z - y])
sage: C.multiplicity(A([0,0,0,0]))
5
::
sage: A.<x,y,z,w,v> = AffineSpace(GF(23), 5)
sage: C = A.curve([x^8 - y, y^7 - z, z^3 - 1, w^5 - v^3])
sage: Q = A([22,1,1,0,0])
sage: C.multiplicity(Q)
3
::
sage: A.<x,y,z> = AffineSpace(QQ, 3)
sage: C = A.curve([y^2 - x^3, x^2 - z^2])
sage: Q = A([1,1,0])
sage: C.multiplicity(Q)
Traceback (most recent call last):
...
TypeError: (=(1, 1, 0)) is not a point on (=Affine Curve over Rational
Field defined by -x^3 + y^2, x^2 - z^2)
"""
if not self.base_ring() in Fields():
raise TypeError("curve must be defined over a field")

# Check whether P is a point on this curve
try:
P = self(P)
except TypeError:
raise TypeError("(=%s) is not a point on (=%s)"%(P,self))

# Apply a linear change of coordinates to self so that P is sent to the origin
# and then compute the multiplicity of the local ring of the translated curve
# corresponding to the point (0,...,0)
AA = self.ambient_space()
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 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``.
Expand Down Expand Up @@ -448,6 +517,184 @@ def is_transverse(self, C, P):
# there is only one tangent at a nonsingular point of a plane curve
return not self.tangents(P)[0] == C.tangents(P)[0]

def multiplicity(self, P):
r"""
Return the multiplicity of this affine plane curve at the point ``P``.
In the special case of affine plane curves, the multiplicity of an affine
plane curve at the point (0,0) can be computed as the minimum of the degrees
of the homogeneous components of its defining polynomial. To compute the
multiplicity of a different point, a linear change of coordinates is used.
This curve must be defined over a field. An error if raised if ``P`` is
not a point on this curve.
INPUT:
- ``P`` -- a point in the ambient space of this curve.
OUTPUT:
An integer.
EXAMPLES::
sage: A.<x,y> = AffineSpace(QQ, 2)
sage: C = Curve([y^2 - x^3], A)
sage: Q1 = A([1,1])
sage: C.multiplicity(Q1)
1
sage: Q2 = A([0,0])
sage: C.multiplicity(Q2)
2
::
sage: A.<x,y> = AffineSpace(QQbar,2)
sage: C = Curve([-x^7 + (-7)*x^6 + y^6 + (-21)*x^5 + 12*y^5 + (-35)*x^4 + 60*y^4 +\
(-35)*x^3 + 160*y^3 + (-21)*x^2 + 240*y^2 + (-7)*x + 192*y + 63], A)
sage: Q = A([-1,-2])
sage: C.multiplicity(Q)
6
::
sage: A.<x,y> = AffineSpace(QQ, 2)
sage: C = A.curve([y^3 - x^3 + x^6])
sage: Q = A([1,1])
sage: C.multiplicity(Q)
Traceback (most recent call last):
...
TypeError: (=(1, 1)) is not a point on (=Affine Plane Curve over
Rational Field defined by x^6 - x^3 + y^3)
"""
if not self.base_ring() in Fields():
raise TypeError("curve must be defined over a field")

# Check whether P is a point on this curve
try:
P = self(P)
except TypeError:
raise TypeError("(=%s) is not a point on (=%s)"%(P,self))

# Apply a linear change of coordinates to self so that P becomes (0,0)
AA = self.ambient_space()
f = self.defining_polynomials()[0](AA.gens()[0] + P[0], AA.gens()[1] + P[1])

# Compute the multiplicity of the new curve at (0,0), which is the minimum of the degrees of its
# nonzero terms
return min([g.degree() for g in f.monomials()])

def tangents(self, P):
r"""
Return the tangents of this affine plane curve at the point ``P``.
The point ``P`` must be a point on this curve.
INPUT:
- ``P`` -- a point on this curve.
OUTPUT:
- a list of polynomials in the coordinate ring of the ambient space of this curve.
EXAMPLES::
sage: R.<a> = QQ[]
sage: K.<b> = NumberField(a^2 - 3)
sage: A.<x,y> = AffineSpace(K, 2)
sage: C = Curve([(x^2 + y^2 - 2*x)^2 - x^2 - y^2], A)
sage: Q = A([0,0])
sage: C.tangents(Q)
[x + (-1/3*b)*y, x + (1/3*b)*y]
::
sage: A.<x,y> = AffineSpace(QQ, 2)
sage: C = A.curve([y^2 - x^3 - x^2])
sage: Q = A([0,0])
sage: C.tangents(Q)
[x - y, x + y]
::
sage: A.<x,y> = AffineSpace(QQ, 2)
sage: C = A.curve([y*x - x^4 + 2*x^2])
sage: Q = A([1,1])
sage: C.tangents(Q)
Traceback (most recent call last):
...
TypeError: (=(1, 1)) is not a point on (=Affine Plane Curve over
Rational Field defined by -x^4 + 2*x^2 + x*y)
"""
r = self.multiplicity(P)
f = self.defining_polynomials()[0]
vars = self.ambient_space().gens()
deriv = [f.derivative(vars[0],i).derivative(vars[1],r-i)(list(P)) for i in range(r+1)]
from sage.arith.misc import binomial
T = sum([binomial(r,i)*deriv[i]*(vars[0] - P[0])**i*(vars[1] - P[1])**(r-i) for i in range(r+1)])
fact = T.factor()
return [l[0] for l in fact]

def is_ordinary_singularity(self, P):
r"""
Return whether the singular point ``P`` of this affine plane curve is an ordinary singularity.
The point ``P`` is an ordinary singularity of this curve if it is a singular point, and
if the tangents of this curve at ``P`` are distinct.
INPUT:
- ``P`` -- a point on this curve.
OUTPUT:
- Boolean. True or False depending on whether ``P`` is or is not an ordinary singularity of this
curve, respectively. An error is raised if ``P`` is not a singular point of this curve.
EXAMPLES::
sage: A.<x,y> = AffineSpace(QQ, 2)
sage: C = Curve([y^2 - x^3], A)
sage: Q = A([0,0])
sage: C.is_ordinary_singularity(Q)
False
::
sage: R.<a> = QQ[]
sage: K.<b> = NumberField(a^2 - 3)
sage: A.<x,y> = AffineSpace(K, 2)
sage: C = Curve([(x^2 + y^2 - 2*x)^2 - x^2 - y^2], A)
sage: Q = A([0,0])
sage: C.is_ordinary_singularity(Q)
True
::
sage: A.<x,y> = AffineSpace(QQ, 2)
sage: C = A.curve([x^2*y - y^2*x + y^2 + x^3])
sage: Q = A([-1,-1])
sage: C.is_ordinary_singularity(Q)
Traceback (most recent call last):
...
TypeError: (=(-1, -1)) is not a singular point of (=Affine Plane Curve
over Rational Field defined by x^3 + x^2*y - x*y^2 + y^2)
"""
r = self.multiplicity(P)
if r < 2:
raise TypeError("(=%s) is not a singular point of (=%s)"%(P,self))

T = self.tangents(P)

# when there is a tangent of higher multiplicity
if len(T) < r:
return False

# otherwise they are distinct
return True

class AffinePlaneCurve_finite_field(AffinePlaneCurve):
def rational_points(self, algorithm="enum"):
r"""
Expand Down
115 changes: 114 additions & 1 deletion src/sage/schemes/curves/curve.py
Expand Up @@ -3,7 +3,7 @@
"""

from sage.categories.finite_fields import FiniteFields

from sage.categories.fields import Fields
from sage.misc.all import latex

from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme
Expand Down Expand Up @@ -197,6 +197,119 @@ def union(self, other):

__add__ = union

def singular_subscheme(self):
r"""
Return the subscheme of singular points of this curve.
OUTPUT:
- a subscheme in the ambient space of this curve.
EXAMPLES::
sage: A.<x,y> = AffineSpace(CC, 2)
sage: C = Curve([y^4 - 2*x^5 - x^2*y], A)
sage: C.singular_subscheme()
Closed subscheme of Affine Space of dimension 2 over Complex Field with
53 bits of precision defined by:
(-2.00000000000000)*x^5 + y^4 - x^2*y,
(-10.0000000000000)*x^4 + (-2.00000000000000)*x*y,
4.00000000000000*y^3 - x^2
::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
sage: C = Curve([y^8 - x^2*z*w^5, w^2 - 2*y^2 - x*z], P)
sage: C.singular_subscheme()
Closed subscheme of Projective Space of dimension 3 over Rational Field
defined by:
y^8 - x^2*z*w^5,
-2*y^2 - x*z + w^2,
-x^3*y*z^4 + 3*x^2*y*z^3*w^2 - 3*x*y*z^2*w^4 + 8*x*y*z*w^5 + y*z*w^6,
x^2*z*w^5,
-5*x^2*z^2*w^4 - 4*x*z*w^6,
x^4*y*z^3 - 3*x^3*y*z^2*w^2 + 3*x^2*y*z*w^4 - 4*x^2*y*w^5 - x*y*w^6,
-2*x^3*y*z^3*w + 6*x^2*y*z^2*w^3 - 20*x^2*y*z*w^4 - 6*x*y*z*w^5 +
2*y*w^7,
-5*x^3*z*w^4 - 2*x^2*w^6
"""
return self.ambient_space().subscheme(self.Jacobian())

def singular_points(self, F=None):
r"""
Return the set of singular points of this curve.
INPUT:
- ``F`` -- (default: None) field over which to find the singular points. If not given,
the base ring of this curve is used.
OUTPUT:
- a list of points in the ambient space of this curve.
EXAMPLES::
sage: A.<x,y,z> = AffineSpace(QQ, 3)
sage: C = Curve([y^2 - x^5, x - z], A)
sage: C.singular_points()
[(0, 0, 0)]
::
sage: R.<a> = QQ[]
sage: K.<b> = NumberField(a^8 - a^4 + 1)
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: C = Curve([359/12*x*y^2*z^2 + 2*y*z^4 + 187/12*y^3*z^2 + x*z^4\
+ 67/3*x^2*y*z^2 + 117/4*y^5 + 9*x^5 + 6*x^3*z^2 + 393/4*x*y^4\
+ 145*x^2*y^3 + 115*x^3*y^2 + 49*x^4*y], P)
sage: C.singular_points(K)
[(1/2*b^5 + 1/2*b^3 - 1/2*b - 1 : 1 : 0), (-2/3*b^4 + 1/3 : 0 : 1),
(2/3*b^4 - 1/3 : 0 : 1), (b^6 : -b^6 : 1), (-b^6 : b^6 : 1),
(-1/2*b^5 - 1/2*b^3 + 1/2*b - 1 : 1 : 0)]
"""
if F is None:
if not self.base_ring() in Fields():
raise TypeError("curve must be defined over a field")
elif not F in Fields():
raise TypeError("(=%s) must be a field"%F)
X = self.singular_subscheme()
return X.rational_points(F=F)

def is_singular(self, P=None):
r"""
Return whether ``P`` is a singular point of this curve, or if no point is passed,
whether this curve is singular or not.
This just uses the is_smooth function for algebraic subschemes.
INPUT:
- ``P`` -- (default: None) a point on this curve.
OUTPUT:
- Boolean. If a point ``P`` is provided, and if ``P`` lies on this curve, returns True
if ``P`` is a singular point of this curve, and False otherwise. If no point is provided,
returns True or False depending on whether this curve is or is not singular, respectively.
EXAMPLES::
sage: P.<x,y,z,w> = ProjectiveSpace(QQ, 3)
sage: C = P.curve([y^2 - x^2 - z^2, z - w])
sage: C.is_singular()
False
::
sage: A.<x,y,z> = AffineSpace(GF(11), 3)
sage: C = A.curve([y^3 - z^5, x^5 - y + 1])
sage: Q = A([7,0,0])
sage: C.is_singular(Q)
True
"""
return not self.is_smooth(P)

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``.
Expand Down

0 comments on commit 6564724

Please sign in to comment.