# Ticket #727: trac_727-conic.patch

File trac_727-conic.patch, 17.5 KB (added by Marco Streng, 13 years ago)

Define a Conic class with an interface to Denis Simon's qfsolve

• ## sage/schemes/plane_curves/constructor.py

# HG changeset patch
# User Marco Streng <marco.streng@gmail.com>
# Date 1245316852 -3600
# Node ID 0c3d0a49c689e35972e9ab37f1a3b354713236ce
# Parent  5f46e0147001357af9779b11e9658b6c53fd6caa
Integrate code of Denis Simon for finding points on rational conics.

diff -r 5f46e0147001 -r 0c3d0a49c689 sage/schemes/plane_curves/constructor.py
 a #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.rings.all import is_MPolynomial, is_MPolynomialRing, is_FiniteField from sage.rings.all import PolynomialRing, is_MPolynomial, is_MPolynomialRing, is_FiniteField from sage.structure.all import Sequence from sage.structure.element import is_Matrix from sage.schemes.generic.all import (is_AmbientSpace, is_AlgebraicScheme, AffineSpace, ProjectiveSpace) from sage.modules.free_module_element import vector import affine_curve ProjectiveSpaceCurve_generic, ProjectiveCurve_finite_field, ProjectiveCurve_prime_finite_field) from projective_conic import (ProjectiveConic_generic) from affine_curve import (AffineCurve_generic, AffineSpaceCurve_generic, 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. Return the plane or space curve defined by `F`, where `F` can be either a multivariate polynomial, a list or tuple of polynomials, an algebraic scheme, or a square matrix. If `F` is in two variables the curve is affine, and if it is homogenous in `3` variables, then the curve is projective. 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: Curve((x-y)*(x+y)) Projective Curve over Rational Field defined by x^2 - y^2 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 sage: x,y,z = QQ['x,y,z'].gens() sage: Curve(x^2+y^2) Projective Curve over Rational Field defined by 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): ... Traceback (most recent call last): ... ValueError: defining polynomial of curve must be nonzero Plane curves are often represented by matrices:: sage: Curve(matrix(QQ, [[2, 3], [4, 5]])) Affine Curve over Rational Field defined by 2*x^2 + 7*x*y + 5*y^2 sage: x,y,z = GF(11)['x,y,z'].gens() sage: C = Curve(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: Curve(C.symmetric_matrix()) Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 """ if is_AlgebraicScheme(F): return Curve(F.defining_polynomials()) if isinstance(F, (list, tuple)): if len(F) == 1: return Curve(F[0]) A = ProjectiveSpace(P.ngens()-1, P.base_ring()) A._coordinate_ring = P return ProjectiveSpaceCurve_generic(A, F) if is_Matrix(F) and F.is_square(): if F.ncols() == 2: temp_ring = PolynomialRing(F.parent().base_ring(), F.ncols(), 'x, y') elif F.ncols() == 3: temp_ring = PolynomialRing(F.parent().base_ring(), F.ncols(), 'x, y, z') else: temp_ring = PolynomialRing(F.parent().base_ring(), F.ncols(), 'x') F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) if not is_MPolynomial(F): raise TypeError, "F (=%s) must be a multivariate polynomial"%F if F == 0: raise ValueError, "defining polynomial of curve must be nonzero" 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 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" return AffineCurve_generic(A2, F) if F.parent().ngens() == 3: P2 = ProjectiveSpace(2, P.base_ring()) P2._coordinate_ring = P if F.total_degree() == 2: return ProjectiveConic_generic(P2, 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) return ProjectiveCurve_generic(P2, F) else: raise TypeError, "Number of variables of F (=%s) must be 2 or 3"%F raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
• ## new file sage/schemes/plane_curves/projective_conic.py

diff -r 5f46e0147001 -r 0c3d0a49c689 sage/schemes/plane_curves/projective_conic.py
 - r""" Projective plane conics over a general ring. Let M be a 3-by-3 matrix.  We denote by X_M the projective variety defined by (x, y, z) M (x, y, z)^t = 0. AUTHORS: -- 2008-01-08, Nick Alexander """ #***************************************************************************** #       Copyright (C) 2008 William Stein # #  Distributed under the terms of the GNU General Public License (GPL) # #  The full text of the GPL is available at: # #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.libs.pari.gen import pari from sage.misc.all import add, sage_eval from sage.rings.all import (PolynomialRing, ZZ, QQ, MPolynomialRing, degree_lowest_rational_function, is_PrimeField) from sage.modules.free_module_element import vector from sage.structure.sequence import Sequence from sage.schemes.generic.projective_space import is_ProjectiveSpace from curve import Curve_generic_projective from projective_curve import ProjectiveCurve_generic from qfsolve import Qfsolve, Qfparam from wamelen import diagsymm class ProjectiveConic_generic(ProjectiveCurve_generic): def __init__(self, A, f): ProjectiveCurve_generic.__init__(self, A, f) # We cache some things self._diagonal_matrix = None self._diagonal_transform = None self._symmetric_matrix = None self._rational_point = None self._parametrization = None def _repr_type(self): return "Projective Conic" def symmetric_matrix(self): r"""A symmetric matrix M such that (x y z) M (x y z)^t = self. That is, X_M has defining equation the same as self. EXAMPLES: sage: R. = QQ[] sage: C = Curve(x^2 + y^2 + z^2) sage: C.symmetric_matrix() [1 0 0] [0 1 0] [0 0 1] sage: C = Curve(x^2 + 2*x*y + y^2 + 3*x*z + z^2) sage: v = vector([x, y, z]) sage: v * C.symmetric_matrix() * v x^2 + 2*x*y + y^2 + 3*x*z + z^2 TESTS: sage: C = Curve(2*x^2 + 3*y^2 + 4*z^2) sage: C.symmetric_matrix() [2 0 0] [0 3 0] [0 0 4] """ if self._symmetric_matrix is not None: return self._symmetric_matrix from sage.matrix.constructor import matrix b = self.defining_polynomial() M = matrix([[ b[(2,0,0)]  , b[(1,1,0)]/2, b[(1,0,1)]/2 ], [ b[(1,1,0)]/2, b[(0,2,0)]  , b[(0,1,1)]/2 ], [ b[(1,0,1)]/2, b[(0,1,1)]/2, b[(0,0,2)]   ]]) self._symmetric_matrix = M return self._symmetric_matrix def normalized_symmetric_matrix(self): # Qfsolve barfs on matrices that have non-trivial denominator content from sage.rings.arith import lcm from constructor import Curve M = self.symmetric_matrix() M *= lcm([ t.denominator() for t in M.list() ]) return M # F = self.defining_polynomial() # return Curve(F * lcm([ t.denominator() for t in F.coefficients() ])).symmetric_matrix() def determinant(self): r""" XXX """ return self.symmetric_matrix().determinant() def discriminant(self): r""" XXX """ return self.defining_polynomial().discriminant() def diagonal_matrix(self): r"""A diagonal matrix D and a matrix Phi such that self and X_D are isomorphic via Phi. EXAMPLES: sage: R. = QQ[] sage: C = Curve(12*x^2 - 2*y^2 + 5*x*z + 5*z^2) sage: D, Phi = C.diagonal_matrix(); D [    12      0      0] [     0     -2      0] [     0      0 215/48] Let's test the isomorphism.  First, at a single point: sage: P = C.rational_point(); P (1/3 : -2 : 1) sage: Q = vector(P) * Phi.inverse(); Q (13/24, -2, 1) sage: Q * D * Q 0 Second, on a parametrization: sage: X = Curve(D); X Projective Conic Curve over Rational Field defined by 12*x^2 - 2*y^2 + 215/48*z^2 sage: param = C.parametrization(); param (3*t^2 - 14*t + 13, -7*t^2 + 31*t - 42, -2*t^2 + 12) sage: X.defining_polynomial()(*param * Phi.inverse()) 0 """ if self._diagonal_matrix is not None: return (self._diagonal_matrix, self._diagonal_transform) M = self.symmetric_matrix() P = diagsymm(M) self._diagonal_transform = P self._diagonal_matrix = P * M * P.transpose() return (self._diagonal_matrix, self._diagonal_transform) standard_matrix = diagonal_matrix def rational_point(self): r"""Return a rational point (x0, y0, z0) on self. Raises ValueError if no rational point exists.  XXX Fixme ALGORITHM: Uses Denis Simon's Qfsolve. EXAMPLES: sage: R. = QQ[] sage: C = Curve(7*x^2 + 2*y*z + z^2) sage: C.rational_point() (0 : 1 : 0) sage: C = Curve(x^2 + 2*y^2 + z^2) sage: C.rational_point() Traceback (most recent call last): ... ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field! sage: C = Curve(x^2 + y^2 + 7*z^2) sage: C.rational_point() Traceback (most recent call last): ... ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field! """ if self._rational_point is not None: return self._rational_point pt = Qfsolve(self.normalized_symmetric_matrix()) if pt in ZZ: raise ValueError, "Conic %s has no rational points over %s!" % (self, self.ambient_space().base_ring()) self._rational_point = self.ambient_space()(pt[0], pt[1], pt[2]) return self._rational_point def parametrization(self): r"""Return a rational point (x0, y0, z0) on self. Raises ValueError if no rational point exists.  XXX Fixme ALGORITHM: Uses Denis Simon's Qfsolve and Qfparam. EXAMPLES: sage: R. = QQ[] sage: C = Curve(7*x^2 + 2*y*z + z^2) sage: P = C.parametrization(); P (-2*t, 7*t^2 + 1, -2) sage: C.defining_polynomial()(*P) 0 sage: C = Curve(x^2 + 2*y^2 + z^2) sage: C.parametrization() Traceback (most recent call last): ... ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field! sage: C = Curve(x^2 + y^2 + 7*z^2) sage: C.parametrization() Traceback (most recent call last): ... ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field! """ if self._parametrization is not None: return self._parametrization return vector(list(Qfparam(self.symmetric_matrix(), list(self.rational_point())))) param = parametrization
• ## new file sage/schemes/plane_curves/qfsolve.py

diff -r 5f46e0147001 -r 0c3d0a49c689 sage/schemes/plane_curves/qfsolve.py