Ticket #727: trac_727_conics.patch

File trac_727_conics.patch, 95.6 KB (added by Marco Streng, 12 years ago)

Apply trac_727_conics.patch to sage 4.6 after #2329 and #9334

  • doc/en/reference/plane_curves.rst

    # HG changeset patch
    # User Marco Streng <marco.streng@gmail.com>
    # Date 1291829172 0
    # Node ID bbbd71be40afcfefffcfe8d8ca63c13f3d7c0cc5
    # Parent  0bada77b22e6b5626d4665d8dcf831098ef3a29f
    Trac 727: conics
    
    diff -r 0bada77b22e6 -r bbbd71be40af doc/en/reference/plane_curves.rst
    a b  
    1111   sage/schemes/plane_curves/affine_curve
    1212   sage/schemes/plane_curves/projective_curve
    1313
     14   sage/schemes/plane_conics/constructor
     15   sage/schemes/plane_conics/con_field
     16   sage/schemes/plane_conics/con_number_field
     17   sage/schemes/plane_conics/con_rational_field
     18   sage/schemes/plane_conics/con_finite_field
     19   sage/schemes/plane_conics/con_prime_finite_field
     20
    1421   sage/schemes/elliptic_curves/constructor
    1522   sage/schemes/elliptic_curves/ell_generic
    1623   sage/schemes/elliptic_curves/ell_field
  • new file sage/quadratic_forms/qfsolve.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/quadratic_forms/qfsolve.py
    - +  
     1"""
     2qfsolve: Programme de resolution des equations quadratiques.
     3
     4Interface to the GP quadratic forms code of Denis Simon.
     5
     6AUTHORS:
     7
     8 * Denis Simon (GP code)
     9
     10 * Nick Alexander (Sage interface)
     11"""
     12
     13#*****************************************************************************
     14#       Copyright (C) 2008 Nick Alexander
     15#
     16#  Distributed under the terms of the GNU General Public License (GPL)
     17#
     18#    This code is distributed in the hope that it will be useful,
     19#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     20#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21#    General Public License for more details.
     22#
     23#  The full text of the GPL is available at:
     24#
     25#                  http://www.gnu.org/licenses/
     26#*****************************************************************************
     27
     28from sage.interfaces.gp import Gp
     29from sage.rings.all import ZZ, QQ
     30from sage.libs.pari.gen import pari
     31
     32_gp_for_simon_interpreter = None    # Global GP interpreter for Denis Simon's code
     33def _gp_for_simon():
     34    r"""
     35    Start a GP interpreter for the use of Denis Simon's Qfsolve and Qfparam
     36    if it is not started already.
     37   
     38    EXAMPLE ::
     39   
     40        sage: from sage.quadratic_forms.qfsolve import _gp_for_simon
     41        sage: _gp_for_simon()
     42        GP/PARI interpreter
     43    """
     44    global _gp_for_simon_interpreter
     45    if _gp_for_simon_interpreter is None:
     46        _gp_for_simon_interpreter = Gp(script_subdirectory='simon')
     47        _gp_for_simon_interpreter.read("qfsolve.gp")
     48    return _gp_for_simon_interpreter
     49
     50# \\ - Qfsolve(G,factD): pour resoudre l'equation quadratique X^t*G*X = 0
     51# \\ G doit etre une matrice symetrique n*n, a coefficients dans Z.
     52# \\ S'il n'existe pas de solution, la reponse est un entier
     53# \\ indiquant un corps local dans lequel aucune solution n'existe
     54# \\ (-1 pour les reels, p pour Q_p).
     55# \\ Si on connait la factorisation de -abs(2*matdet(G)),
     56# \\ on peut la passer par le parametre factD pour gagner du temps.
     57# \\
     58# \\ - Qfparam(G,sol,fl): pour parametrer les solutions de la forme
     59# \\ quadratique ternaire G, en utilisant la solution particuliere sol.
     60# \\ si fl>0, la 'fl'eme forme quadratique est reduite.
     61
     62def qfsolve(G, factD=None):
     63    r"""
     64    Find a solution `x = (x_0,...,x_n)` to `x G x^t = 0` for an
     65    `n \times n`-matrix ``G`` over `\QQ`.
     66
     67    If a solution exists, returns a tuple of rational numbers `x`.
     68    Otherwise, returns `-1` if no solutions exists over the reals or a
     69    prime `p` if no solution exists over the `p`-adic field `\QQ_p`.
     70
     71    EXAMPLES::
     72
     73        sage: from sage.quadratic_forms.qfsolve import qfsolve
     74        sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M
     75        [  0   0 -12]
     76        [  0 -12   0]
     77        [-12   0  -1]
     78        sage: sol = qfsolve(M); sol
     79        (1, 0, 0)
     80        sage: sol[0].parent() is QQ
     81        True
     82       
     83        sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
     84        sage: ret = qfsolve(M); ret
     85        -1
     86        sage: ret.parent() is ZZ
     87        True
     88
     89        sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, -7]])
     90        sage: qfsolve(M)
     91        7
     92
     93        sage: M = Matrix(QQ, [[3, 0, 0, 0], [0, 5, 0, 0], [0, 0, -7, 0], [0, 0, 0, -11]])
     94        sage: qfsolve(M)
     95        (-3, 4, 3, 2)
     96    """
     97    gp = _gp_for_simon()
     98    if factD is not None:
     99        raise NotImplementedError, "qfsolve not implemented with parameter factD"
     100    ret = pari(gp('Qfsolve(%s)' % G._pari_()))
     101    if ret.type() == 't_COL':
     102        return tuple([QQ(r) for r in ret])
     103    return ZZ(ret)
     104
     105def qfparam(G, sol):
     106    r"""
     107    Parametrizes the conic defined by the matrix ``G``.
     108
     109    INPUT:
     110
     111     - ``G`` -- a `3 \times 3`-matrix over `\QQ`.
     112
     113     - ``sol`` -- a triple of rational numbers providing a solution
     114       to sol*G*sol^t = 0.
     115
     116    OUTPUT:
     117
     118    A triple of polynomials that parametrizes all solutions of
     119    x*G*x^t = 0 up to scaling.
     120
     121    ALGORITHM:
     122
     123    Uses Denis Simon's pari script Qfparam.
     124
     125    EXAMPLES::
     126
     127        sage: from sage.quadratic_forms.qfsolve import qfsolve, qfparam
     128        sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M
     129        [  0   0 -12]
     130        [  0 -12   0]
     131        [-12   0  -1]
     132        sage: sol = qfsolve(M);
     133        sage: ret = qfparam(M, sol); ret
     134        (-t^2 - 12, 24*t, 24*t^2)
     135        sage: ret[0].parent() is QQ['t']
     136        True
     137    """
     138    gp = _gp_for_simon()
     139    R = QQ['t']
     140    t = R.gen()
     141    s = 'Qfparam(%s, (%s)~)*[t^2,t,1]~' % (G._pari_(), pari(gp(sol))._pari_())
     142    ret = pari(gp(s))
     143    return tuple([R(r) for r in ret])
     144
  • sage/schemes/all.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/all.py
    a b  
    2626
    2727from plane_curves.all import *
    2828
     29from plane_conics.all import *
     30
    2931from elliptic_curves.all import *
    3032
    3133from plane_quartics.all import *
  • new file sage/schemes/plane_conics/__init__.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/__init__.py
    - +  
     1
     2
  • new file sage/schemes/plane_conics/all.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/all.py
    - +  
     1"""
     2Plane conics
     3"""
     4
     5#*****************************************************************************
     6#
     7#   SAGE: System for Algebra and Geometry Experimentation   
     8#
     9#       Copyright (C) 2005 William Stein <was@math.harvard.edu>
     10#
     11#  Distributed under the terms of the GNU General Public License (GPL)
     12#
     13#    This code is distributed in the hope that it will be useful,
     14#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16#    General Public License for more details.
     17#
     18#  The full text of the GPL is available at:
     19#
     20#                  http://www.gnu.org/licenses/
     21#*****************************************************************************
     22
     23from constructor import Conic
     24
     25
  • new file sage/schemes/plane_conics/con_field.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/con_field.py
    - +  
     1r"""
     2Projective plane conics over a field.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-07-20)
     7
     8- Nick Alexander (2008-01-08)
     9
     10"""
     11#*****************************************************************************
     12#       Copyright (C) 2008 Nick Alexander <ncalexander@gmail.com>
     13#       Copyright (C) 2009/2010 Marco Streng <marco.streng@gmail.com>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#
     17#    This code is distributed in the hope that it will be useful,
     18#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     19#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     20#    General Public License for more details.
     21#
     22#  The full text of the GPL is available at:
     23#
     24#                  http://www.gnu.org/licenses/
     25#*****************************************************************************
     26
     27from sage.rings.all import (PolynomialRing, QQ,
     28                            is_ComplexField, is_RealField,
     29                            is_Field)
     30from sage.modules.free_module_element import vector
     31from sage.structure.sequence import Sequence
     32from sage.structure.element import is_Vector
     33from sage.schemes.generic.projective_space import ProjectiveSpace
     34from sage.matrix.constructor import Matrix
     35from sage.matrix.matrix import is_Matrix
     36
     37from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic
     38
     39class ProjectiveConic_field(ProjectiveCurve_generic):
     40    r"""
     41    Create a projective plane conic curve over a field.
     42    See ``Conic`` for full documentation.
     43   
     44    EXAMPLES::
     45   
     46        sage: K = FractionField(PolynomialRing(QQ, 't'))
     47        sage: P.<X, Y, Z> = K[]
     48        sage: Conic(X^2 + Y^2 - Z^2)
     49        Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by X^2 + Y^2 - Z^2
     50       
     51    TESTS::
     52   
     53        sage: K = FractionField(PolynomialRing(QQ, 't'))
     54        sage: Conic([K(1), 1, -1])._test_pickling()
     55    """
     56    def __init__(self, A, f):
     57        r"""
     58        See ``Conic`` for full documentation.
     59
     60        EXAMPLES:
     61
     62        ::
     63
     64            sage: c = Conic([1, 1, 1]); c
     65            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     66        """
     67        ProjectiveCurve_generic.__init__(self, A, f)
     68        self._coefficients = [f[(2,0,0)], f[(1,1,0)], f[(1,0,1)],
     69                                f[(0,2,0)], f[(0,1,1)], f[(0,0,2)]]
     70        self._parametrization = None
     71        self._diagonal_matrix = None
     72       
     73        self._rational_point = None
     74
     75
     76
     77
     78    def _repr_type(self):
     79        r"""
     80        Returns ``'Projective Conic'``, which is the first part of the
     81        plain text representation of this object as output by
     82        the function ``_repr_`` of the class ``Curve_generic``.
     83
     84        EXAMPLES::
     85
     86            sage: c = Conic([1, 1, 1]); c
     87            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     88            sage: c._repr_()
     89            'Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2'
     90            sage: c._repr_type()
     91            'Projective Conic'
     92        """
     93        return "Projective Conic"
     94
     95    def base_extend(self, S):
     96        r"""
     97        Returns the conic over ``S`` given by the same equation as ``self``.
     98
     99        EXAMPLES::
     100
     101            sage: c = Conic([1, 1, 1]); c
     102            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     103            sage: c.has_rational_point()
     104            False
     105            sage: d = c.base_extend(QuadraticField(-1, 'i')); d
     106            Projective Conic Curve over Number Field in i with defining polynomial x^2 + 1 defined by x^2 + y^2 + z^2
     107            sage: d.rational_point(algorithm = 'rnfisnorm')
     108            (i : 1 : 0)
     109        """
     110        if is_Field(S):
     111            B = self.base_ring()
     112            if B == S:
     113                return self
     114            if not S.has_coerce_map_from(B):
     115                raise ValueError, "No natural map from the base ring of self " \
     116                                  "(= %s) to S (= %s)" % (self, S)
     117            from constructor import Conic
     118            con = Conic([S(c) for c in self.coefficients()], \
     119                        self.variable_names())
     120            if self._rational_point != None:
     121                pt = [S(c) for c in Sequence(self._rational_point)]
     122                if not pt == [0,0,0]:
     123                    # The following line stores the point in the cache
     124                    # if (and only if) there is no point in the cache.
     125                    pt = con.point(pt)
     126            return con
     127        return ProjectiveCurve_generic.base_extend(self, S)
     128   
     129    def cache_point(self, p):
     130        r"""
     131        Replace the point in the cache of ``self`` by ``p`` for use
     132        by ``self.rational_point()`` and ``self.parametrization()``.
     133       
     134        EXAMPLES::
     135
     136            sage: c = Conic([1, -1, 1])
     137            sage: c.point([15, 17, 8])
     138            (15/8 : 17/8 : 1)
     139            sage: c.rational_point()
     140            (15/8 : 17/8 : 1)
     141            sage: c.cache_point(c.rational_point(read_cache = False))
     142            sage: c.rational_point()
     143            (1 : 1 : 0)
     144        """
     145        if isinstance(p, (tuple, list)):
     146            p = self.point(p)
     147        self._rational_point = p
     148
     149    def coefficients(self):
     150        r"""
     151        Gives a the `6` coefficients of the conic ``self``
     152        in lexicographic order.
     153       
     154        EXAMPLES::
     155       
     156            sage: Conic(QQ, [1,2,3,4,5,6]).coefficients()
     157            [1, 2, 3, 4, 5, 6]
     158
     159            sage: P.<x,y,z> = GF(13)[]
     160            sage: a = Conic(x^2+5*x*y+y^2+z^2).coefficients(); a
     161            [1, 5, 0, 1, 0, 1]
     162            sage: Conic(a)
     163            Projective Conic Curve over Finite Field of size 13 defined by x^2 + 5*x*y + y^2 + z^2
     164        """
     165        return self._coefficients
     166       
     167       
     168    def derivative_matrix(self):
     169        r"""
     170        Gives the derivative of the defining polynomial of
     171        the conic ``self``, which is a linear map,
     172        as a `3 \times 3` matrix.
     173       
     174        EXAMPLES:
     175       
     176        In characteristic different from `2`, the
     177        derivative matrix is twice the symmetric matrix:
     178
     179        ::
     180       
     181            sage: c = Conic(QQ, [1,1,1,1,1,0])
     182            sage: c.symmetric_matrix()
     183            [  1 1/2 1/2]
     184            [1/2   1 1/2]
     185            [1/2 1/2   0]
     186            sage: c.derivative_matrix()
     187            [2 1 1]
     188            [1 2 1]
     189            [1 1 0]
     190
     191        An example in characteristic `2`:
     192
     193        ::
     194
     195            sage: P.<t> = GF(2)[]
     196            sage: c = Conic([t, 1, t^2, 1, 1, 0]); c
     197            Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + x*y + y^2 + t^2*x*z + y*z
     198            sage: c.is_smooth()
     199            True
     200            sage: c.derivative_matrix()
     201            [  0   1 t^2]
     202            [  1   0   1]
     203            [t^2   1   0]
     204        """
     205        from sage.matrix.constructor import matrix
     206        [a,b,c,d,e,f] = self.coefficients()
     207        return matrix([[ 2*a ,   b ,   c ],
     208                       [   b , 2*d ,   e ],
     209                       [   c ,   e , 2*f ]])
     210       
     211    def determinant(self):
     212        r"""
     213        Returns the determinant of the symmetric matrix that defines
     214        the conic ``self``.
     215       
     216        This is defined only if the base field has characteristic
     217        different from `2`.
     218
     219        EXAMPLES:
     220
     221        ::
     222
     223            sage: C = Conic([1,2,3,4,5,6])
     224            sage: C.determinant()
     225            41/4
     226            sage: C.symmetric_matrix().determinant()
     227            41/4
     228
     229        Determinants are only defined in characteristic different from `2`::
     230
     231            sage: C = Conic(GF(2), [1, 1, 1, 1, 1, 0])
     232            sage: C.is_smooth()
     233            True
     234            sage: C.determinant()
     235            Traceback (most recent call last):
     236            ...
     237            ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2
     238        """
     239        return self.symmetric_matrix().determinant()
     240
     241    def diagonal_matrix(self):
     242        r"""
     243        Returns a diagonal matrix `D` and a matrix `T` such that `T^t A T = D`
     244        holds, where `(x, y, z) A (x, y, z)^t` is the defining polynomial
     245        of the conic ``self``.
     246
     247        EXAMPLES:
     248
     249        ::
     250
     251            sage: c = Conic(QQ, [1,2,3,4,5,6])
     252            sage: d, t = c.diagonal_matrix(); d, t
     253            (
     254            [    1     0     0]  [   1   -1 -7/6]
     255            [    0     3     0]  [   0    1 -1/3]
     256            [    0     0 41/12], [   0    0    1]
     257            )
     258            sage: t.transpose()*c.symmetric_matrix()*t
     259            [    1     0     0]
     260            [    0     3     0]
     261            [    0     0 41/12]
     262         
     263        Diagonal matrices are only defined in characteristic different
     264        from `2`:
     265       
     266        ::
     267
     268            sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1])
     269            sage: c.is_smooth()
     270            True
     271            sage: c.diagonal_matrix()
     272            Traceback (most recent call last):
     273            ...
     274            ValueError: The conic self (= Projective Conic Curve over Finite Field in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has no symmetric matrix because the base field has characteristic 2
     275        """
     276        A = self.symmetric_matrix()
     277        B = self.base_ring()
     278        basis = [vector(B,{2:0,i:1}) for i in range(3)]
     279        for i in range(3):
     280            zerovalue = (basis[i]*A*basis[i].transpose()== 0)
     281            if zerovalue:
     282                for j in range(i+1,3):
     283                    if basis[j]*A*basis[j].transpose() != 0:
     284                        b = basis[i]
     285                        basis[i] = basis[j]
     286                        basis[j] = b
     287                        zerovalue = False
     288            if zerovalue:
     289                for j in range(i+1,3):
     290                    if basis[i]*A*basis[j].transpose() != 0:
     291                        basis[i] = basis[i]+basis[j]
     292                        zerovalue = False
     293            if not zerovalue:
     294                l = (basis[i]*A*basis[i].transpose())
     295                for j in range(i+1,3):
     296                    basis[j] = basis[j] - \
     297                               (basis[i]*A*basis[j].transpose())/l * basis[i]
     298        T = Matrix(basis).transpose()
     299        return T.transpose()*A*T, T
     300       
     301    def diagonalization(self,names = None):
     302        r"""
     303        Returns a diagonal conic `C`, an isomorphism of schemes `M: C` -> ``self``
     304        and the inverse `N` of `M`.
     305       
     306        EXAMPLES::
     307       
     308            sage: Conic(GF(5), [1,0,1,1,0,1]).diagonalization()           
     309            (Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2,
     310             Scheme morphism:
     311              From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2
     312              To:   Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2
     313              Defn: Defined on coordinates by sending (x : y : z) to
     314                    (x + 2*z : y : z),
     315             Scheme morphism:
     316              From: Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + x*z + z^2
     317              To:   Projective Conic Curve over Finite Field of size 5 defined by x^2 + y^2 + 2*z^2
     318              Defn: Defined on coordinates by sending (x : y : z) to
     319                    (x - 2*z : y : z))
     320
     321        The diagonalization is only defined in characteristic different
     322        from 2:
     323       
     324        ::
     325
     326            sage: Conic(GF(2), [1,1,1,1,1,0]).diagonalization()
     327            Traceback (most recent call last):
     328            ...
     329            ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2
     330        """
     331        if names == None:
     332            names = self.defining_polynomial().parent().variable_names()
     333        from constructor import Conic
     334        D, T = self.diagonal_matrix()
     335        con = Conic(D, names = names)
     336        return con, con.hom(T, self), self.hom(T.inverse(), con)
     337
     338    def gens(self):
     339        r"""
     340        Returns the generators of the coordinate ring of ``self``.
     341       
     342        EXAMPLES:
     343       
     344        ::
     345       
     346            sage: P.<x,y,z> = QQ[]
     347            sage: c = Conic(x^2+y^2+z^2)
     348            sage: c.gens()
     349            (xbar, ybar, zbar)
     350            sage: c.defining_polynomial()(c.gens())
     351            0
     352           
     353        The function ``gens()`` is required for the following construction:
     354       
     355        ::
     356       
     357            sage: C.<a,b,c> = Conic(GF(3), [1, 1, 1])
     358            sage: C
     359            Projective Conic Curve over Finite Field of size 3 defined by a^2 + b^2 + c^2
     360
     361        """
     362        return self.coordinate_ring().gens()
     363
     364    def has_rational_point(self, point = False,
     365                           algorithm = 'default', read_cache = True):
     366        r"""
     367        Returns True if and only if the conic ``self``
     368        has a point over its base field `B`.
     369
     370        If ``point`` is True, then returns a second output, which is
     371        a rational point if one exists.
     372       
     373        Points are cached whenever they are found. Cached information
     374        is used if and only if ``read_cache`` is True.
     375       
     376        EXAMPLES:
     377
     378            sage: Conic(RR, [1, 1, 1]).has_rational_point()
     379            False
     380            sage: Conic(CC, [1, 1, 1]).has_rational_point()
     381            True
     382           
     383            sage: Conic(RR, [1, 2, -3]).has_rational_point(point = True)
     384            (True, (1.73205080756888 : 0.000000000000000 : 1.00000000000000))
     385        """
     386        if read_cache:
     387            if self._rational_point is not None:
     388                if point:
     389                    return True, self._rational_point
     390                else:
     391                    return True
     392        B = self.base_ring()
     393        if is_ComplexField(B):
     394            if point:
     395                [_,_,_,d,e,f] = self._coefficients
     396                if d == 0:
     397                    return True, self.point([0,1,0])
     398                return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1],
     399                                        check = False)
     400            return True
     401        if is_RealField(B):
     402            D, T = self.diagonal_matrix()
     403            [a, b, c] = [D[0,0], D[1,1], D[2,2]]
     404            if a == 0:
     405                ret = True, self.point(T*vector([1,0,0]), check = False)
     406            elif a*c <= 0:
     407                ret = True, self.point(T*vector([(-c/a).sqrt(),0,1]),
     408                                       check = False)
     409            elif b == 0:
     410                ret = True, self.point(T*vector([0,1,0]), check = False)
     411            elif b*c <= 0:
     412                ret = True, self.point(T*vector([0,(-c/b).sqrt(),0,1]),
     413                                       check = False)
     414            else:
     415                ret = False, None
     416            if point:
     417                return ret
     418            return ret[0]
     419        raise NotImplementedError, "has_rational_point not implemented for " \
     420                                   "conics over base field %s" % B
     421       
     422    def has_singular_point(self, point = False):
     423        r"""
     424        Return True if and only if the conic ``self`` has a rational
     425        singular point.
     426       
     427        If ``point`` is True, then also return a rational singular
     428        point (or ``None`` if no such point exists).
     429       
     430        EXAMPLES:
     431       
     432        ::
     433           
     434            sage: c = Conic(QQ, [1,0,1]); c
     435            Projective Conic Curve over Rational Field defined by x^2 + z^2
     436            sage: c.has_singular_point(point = True)
     437            (True, (0 : 1 : 0))
     438           
     439            sage: P.<x,y,z> = GF(7)[]
     440            sage: e = Conic((x+y+z)*(x-y+2*z)); e
     441            Projective Conic Curve over Finite Field of size 7 defined by x^2 - y^2 + 3*x*z + y*z + 2*z^2
     442            sage: e.has_singular_point(point = True)
     443            (True, (2 : 4 : 1))
     444
     445            sage: Conic([1, 1, -1]).has_singular_point()
     446            False
     447            sage: Conic([1, 1, -1]).has_singular_point(point = True)
     448            (False, None)
     449
     450        ``has_singular_point`` is not implemented over all fields
     451        of characteristic `2`. It is implemented over finite fields.
     452
     453        ::
     454
     455            sage: F.<a> = FiniteField(8)
     456            sage: Conic([a, a+1, 1]).has_singular_point(point = True)
     457            (True, (a + 1 : 0 : 1))
     458
     459            sage: P.<t> = GF(2)[]
     460            sage: C = Conic(P, [t,t,1]); C
     461            Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + t*y^2 + z^2
     462            sage: C.has_singular_point(point = False)
     463            Traceback (most recent call last):
     464            ...
     465            NotImplementedError: Sorry, find singular point on conics not implemented over all fields of characteristic 2.
     466        """
     467        if not point:
     468           ret = self.has_singular_point(point = True)
     469           return ret[0]
     470        B = self.base_ring()
     471        if B.characteristic() == 2:
     472            [a,b,c,d,e,f] = self.coefficients()
     473            if b == 0 and c == 0 and e == 0:
     474                for i in range(3):
     475                    if [a, d, f][i] == 0:
     476                        return True, self.point(vector(B, {2:0, i:1}))
     477                if hasattr(a/f, 'is_square') and hasattr(a/f, 'sqrt'):
     478                    if (a/f).is_square():
     479                        return True, self.point([1,0,(a/f).sqrt()])
     480                    if (d/f).is_square():
     481                        return True, self.point([0,1,(d/f).sqrt()])
     482                raise NotImplementedError, "Sorry, find singular point on conics not implemented over all fields of characteristic 2."
     483            pt = [e, c, b]
     484            if self.defining_polynomial()(pt) == 0:
     485                return True, self.point(pt)
     486            return False, None
     487        D = self.symmetric_matrix()
     488        if D.determinant() == 0:
     489            return True, self.point(Sequence(D.right_kernel().gen()))
     490        return False, None
     491
     492    def hom(self, x, Y=None):
     493        r"""
     494        Return the scheme morphism from ``self`` to ``Y`` defined by ``x``.
     495        Here ``x`` can be a matrix or a sequence of polynomials.
     496        If ``Y`` is omitted, then a natural image is found if possible.
     497
     498        EXAMPLES:
     499       
     500        Here are a few Morphisms given by matrices. In the first
     501        example, ``Y`` is omitted, in the second example, ``Y`` is specified.
     502
     503        ::
     504           
     505            sage: c = Conic([-1, 1, 1])
     506            sage: h = c.hom(Matrix([[1,1,0],[0,1,0],[0,0,1]])); h
     507            Scheme morphism:
     508              From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2
     509              To:   Projective Conic Curve over Rational Field defined by -x^2 + 2*x*y + z^2
     510              Defn: Defined on coordinates by sending (x : y : z) to
     511                    (x + y : y : z)
     512            sage: h([-1, 1, 0])
     513            (0 : 1 : 0)
     514
     515            sage: c = Conic([-1, 1, 1])
     516            sage: d = Conic([4, 1, -1])
     517            sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), d)
     518            Scheme morphism:
     519              From: Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2
     520              To:   Projective Conic Curve over Rational Field defined by 4*x^2 + y^2 - z^2
     521              Defn: Defined on coordinates by sending (x : y : z) to
     522                    (1/2*z : y : x)
     523
     524        ``ValueError`` is raised if the wrong codomain ``Y`` is specified:
     525
     526        ::
     527       
     528            sage: c = Conic([-1, 1, 1])
     529            sage: c.hom(Matrix([[0, 0, 1/2], [0, 1, 0], [1, 0, 0]]), c)
     530            Traceback (most recent call last):
     531            ...
     532            ValueError: The matrix x (= [  0   0 1/2]
     533            [  0   1   0]
     534            [  1   0   0]) does not define a map from self (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2) to Y (= Projective Conic Curve over Rational Field defined by -x^2 + y^2 + z^2)
     535        """
     536        if is_Matrix(x):   
     537            from constructor import Conic
     538            y = x.inverse()
     539            A = y.transpose()*self.matrix()*y
     540            im = Conic(A)
     541            if Y == None:
     542                Y = im
     543            else:
     544                q = Y.defining_polynomial()/im.defining_polynomial()
     545                if not (q.numerator().is_constant()
     546                        and q.denominator().is_constant()):
     547                    raise ValueError, "The matrix x (= %s) does not define a " \
     548                                      "map from self (= %s) to Y (= %s)" % \
     549                                      (x, self, Y)
     550            x = Sequence(x*vector(self.ambient_space().gens()))
     551            return self.Hom(Y)(x, check = False)
     552        return ProjectiveCurve_generic.hom(self, x, Y)           
     553           
     554       
     555    def is_diagonal(self):
     556        r"""
     557        Return True if and only if the conic has the form
     558        `a*x^2 + b*y^2 + c*z^2`.
     559
     560        EXAMPLES:
     561
     562        ::
     563
     564            sage: c=Conic([1,1,0,1,0,1]); c
     565            Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + z^2
     566            sage: d,t = c.diagonal_matrix()
     567            sage: c.is_diagonal()
     568            False
     569            sage: c.diagonalization()[0].is_diagonal()
     570            True
     571        """
     572        return all([self.coefficients()[i] == 0 for i in [1,2,4]])
     573
     574
     575    def is_smooth(self):
     576        r"""
     577        Returns True if and only if ``self`` is smooth.
     578
     579        EXAMPLES:
     580
     581        ::
     582
     583            sage: Conic([1,-1,0]).is_smooth()
     584            False
     585            sage: Conic(GF(2),[1,1,1,1,1,0]).is_smooth()
     586            True
     587        """
     588        if self.base_ring().characteristic() == 2:
     589            [a,b,c,d,e,f] = self.coefficients()
     590            if b == 0 and c == 0 and e == 0:
     591                return False
     592            return self.defining_polynomial()([e, c, b]) != 0
     593        return self.determinant() != 0
     594
     595
     596    def matrix(self):
     597        r"""
     598        Returns a matrix `M` such that `(x, y, z) M (x, y, z)^t`
     599        is the defining equation of ``self``.
     600
     601        The matrix `M` is upper triangular if the base field has
     602        characteristic `2` and symmetric otherwise.
     603
     604        EXAMPLES::
     605       
     606            sage: R.<x, y, z> = QQ[]
     607            sage: C = Conic(x^2 + x*y + y^2 + z^2)
     608            sage: C.matrix()
     609            [  1 1/2   0]
     610            [1/2   1   0]
     611            [  0   0   1]
     612
     613            sage: R.<x, y, z> = GF(2)[]
     614            sage: C = Conic(x^2 + x*y + y^2 + x*z + z^2)
     615            sage: C.matrix()
     616            [1 1 1]
     617            [0 1 0]
     618            [0 0 1]
     619        """
     620        if self.base_ring().characteristic() == 2:
     621            return self.upper_triangular_matrix()
     622        return self.symmetric_matrix()
     623       
     624    _matrix_ = matrix
     625
     626    def parametrization(self, point=None, morphism=True):
     627        r"""
     628        Return a parametrization `f` of ``self`` together with the
     629        inverse of `f`.
     630
     631        If ``point`` is specified, then that point is used
     632        for the parametrization. Otherwise, use ``self.rational_point()``
     633        to find a point.
     634           
     635        If ``morphism`` is True, then `f` is returned in the form
     636        of a Scheme morphism. Otherwise, it is a tuple of polynomials
     637        that gives the parametrization.
     638       
     639        EXAMPLES:
     640
     641        An example over a finite field ::
     642       
     643            sage: c = Conic(GF(2), [1,1,1,1,1,0])
     644            sage: c.parametrization()
     645            (Scheme morphism:
     646              From: Projective Space of dimension 1 over Finite Field of size 2
     647              To:   Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
     648            + y^2 + x*z + y*z
     649              Defn: Defined on coordinates by sending (x : y) to
     650                    (x*y + y^2 : x^2 + x*y : x^2 + x*y + y^2),
     651             Scheme morphism:
     652              From: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
     653            + y^2 + x*z + y*z
     654              To:   Projective Space of dimension 1 over Finite Field of size 2
     655              Defn: Defined on coordinates by sending (x : y : z) to
     656                    (y : x))
     657
     658        An example with ``morphism = False`` ::
     659
     660            sage: R.<x,y,z> = QQ[]
     661            sage: C = Curve(7*x^2 + 2*y*z + z^2)
     662            sage: (p, i) = C.parametrization(morphism = False); (p, i)
     663            ([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])
     664            sage: C.defining_polynomial()(p)
     665            0
     666            sage: i[0](p) / i[1](p)
     667            x/y
     668           
     669        A ``ValueError`` is raised if ``self`` has no rational point ::
     670
     671            sage: C = Conic(x^2 + y^2 + 7*z^2)
     672            sage: C.parametrization()
     673            Traceback (most recent call last):
     674            ...
     675            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!
     676           
     677        A ``ValueError`` is raised if ``self`` is not smooth ::
     678       
     679            sage: C = Conic(x^2 + y^2)
     680            sage: C.parametrization()
     681            Traceback (most recent call last):
     682            ...
     683            ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
     684        """
     685        if (not self._parametrization is None) and not point:
     686            par = self._parametrization
     687        else:
     688            if not self.is_smooth():
     689                raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self
     690            if point == None:
     691                point = self.rational_point()
     692            point = Sequence(point)
     693            B = self.base_ring()
     694            Q = PolynomialRing(B, 'x,y')
     695            [x, y] = Q.gens()
     696            gens = self.ambient_space().gens()
     697            P = PolynomialRing(B, 4, ['X', 'Y', 'T0', 'T1'])
     698            [X, Y, T0, T1] = P.gens()
     699            c3 = [j for j in range(2,-1,-1) if point[j] != 0][0]
     700            c1 = [j for j in range(3) if j != c3][0]
     701            c2 = [j for j in range(3) if j != c3 and j != c1][0]
     702            L = [0,0,0]
     703            L[c1] = Y*T1*point[c1] + Y*T0
     704            L[c2] = Y*T1*point[c2] + X*T0
     705            L[c3] = Y*T1*point[c3]
     706            bezout = P(self.defining_polynomial()(L) / T0)
     707            t = [bezout([x,y,0,-1]),bezout([x,y,1,0])]
     708            par = (tuple([Q(p([x,y,t[0],t[1]])/y) for  p in L]),
     709                   tuple([gens[m]*point[c3]-gens[c3]*point[m]
     710                       for m in [c2,c1]]))
     711            if self._parametrization is None:
     712                self._parametrization = par
     713        if not morphism:
     714            return par
     715        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
     716        return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
     717       
     718    def point(self, v, check=True):
     719        r"""
     720        Constructs a point on ``self`` corresponding to the input ``v``.
     721       
     722        If ``check`` is True, then checks if ``v`` defines a valid
     723        point on ``self``.
     724       
     725        If no rational point on ``self`` is known yet, then also caches the point
     726        for use by ``self.rational_point()`` and ``self.parametrization()``.
     727
     728        EXAMPLES ::
     729
     730            sage: c = Conic([1, -1, 1])
     731            sage: c.point([15, 17, 8])
     732            (15/8 : 17/8 : 1)
     733            sage: c.rational_point()
     734            (15/8 : 17/8 : 1)
     735            sage: d = Conic([1, -1, 1])
     736            sage: d.rational_point()
     737            (1 : 1 : 0)
     738        """
     739        if is_Vector(v):
     740            v = Sequence(v)
     741        p = ProjectiveCurve_generic.point(self, v, check=check)
     742        if self._rational_point is None:
     743            self._rational_point = p
     744        return p
     745
     746       
     747    def random_rational_point(self, *args1, **args2):
     748        r"""
     749        Return a random rational point of the conic ``self``.
     750       
     751        ALGORITHM:
     752       
     753            1. Compute a parametrization `f` of ``self`` using
     754               ``self.parametrization()``.
     755            2. Computes a random point `(x:y)` on the projective
     756               line.
     757            3. Output `f(x:y)`.
     758       
     759        The coordinates x and y are computed using
     760        ``B.random_element``, where ``B`` is the base field of
     761        ``self`` and additional arguments to ``random_rational_point``
     762        are passed to ``random_element``.
     763           
     764        If the base field is a finite field, then the
     765        output is uniformly distributed over the points of self.
     766
     767        EXAMPLES ::
     768           
     769            sage: c = Conic(GF(2), [1,1,1,1,1,0])
     770            sage: [c.random_rational_point() for i in range(10)] # output is random
     771            [(1 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 1 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1), (1 : 0 : 1), (0 : 0 : 1), (1 : 0 : 1)]
     772           
     773            sage: d = Conic(QQ, [1, 1, -1])
     774            sage: d.random_rational_point(den_bound = 1, num_bound = 5) # output is random
     775            (-24/25 : 7/25 : 1)
     776           
     777            sage: Conic(QQ, [1, 1, 1]).random_rational_point()
     778            Traceback (most recent call last):
     779            ...
     780            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 has no rational points over Rational Field!
     781
     782        """
     783        if not self.is_smooth():
     784            raise NotImplementedError, "Sorry, random points not implemented " \
     785                                       "for non-smooth conics"
     786        par = self.parametrization()
     787        x = 0
     788        y = 0
     789        B = self.base_ring()
     790        while x == 0 and y == 0:
     791            x = B.random_element(*args1, **args2)
     792            y = B.random_element(*args1, **args2)
     793        return par[0]([x,y])
     794
     795
     796    def rational_point(self, algorithm = 'default', read_cache = True):
     797        r"""
     798        Return a point on ``self`` defined over the base field.
     799
     800        Raises ``ValueError`` if no rational point exists.
     801
     802        See ``self.has_rational_point`` for the algorithm used
     803        and for the use of the parameters ``algorithm`` and ``read_cache``.
     804         
     805        EXAMPLES:
     806
     807        Examples over `\QQ` ::
     808       
     809            sage: R.<x,y,z> = QQ[]
     810            sage: C = Conic(7*x^2 + 2*y*z + z^2)
     811            sage: C.rational_point()
     812            (0 : 1 : 0)
     813
     814            sage: C = Conic(x^2 + 2*y^2 + z^2)
     815            sage: C.rational_point()
     816            Traceback (most recent call last):
     817            ...
     818            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!
     819
     820            sage: C = Conic(x^2 + y^2 + 7*z^2)
     821            sage: C.rational_point(algorithm = 'rnfisnorm')
     822            Traceback (most recent call last):
     823            ...
     824            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!
     825
     826        Examples over number fields ::
     827           
     828            sage: P.<x> = QQ[]
     829            sage: L.<b> = NumberField(x^3-5)
     830            sage: C = Conic(L, [3, 2, -5])
     831            sage: C.rational_point(algorithm = 'rnfisnorm')  # long time (1/2 second), output is random
     832            (37632*b^2 + 88168*b - 260801 : -99528*b^2 + 153348*b + 28799 : 1)
     833       
     834        Examples over finite fields ::
     835       
     836            sage: F.<a> = FiniteField(7^20)
     837            sage: C = Conic([1, a, -5]); C
     838            Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + (a)*y^2 + 2*z^2
     839            sage: C.rational_point()  # output is random
     840            (4*a^19 + 5*a^18 + 4*a^17 + a^16 + 6*a^15 + 3*a^13 + 6*a^11 + a^9 + 3*a^8 + 2*a^7 + 4*a^6 + 3*a^5 + 3*a^4 + a^3 + a + 6 : 5*a^18 + a^17 + a^16 + 6*a^15 + 4*a^14 + a^13 + 5*a^12 + 5*a^10 + 2*a^9 + 6*a^8 + 6*a^7 + 6*a^6 + 2*a^4 + 3 : 1)
     841             
     842        Examples over `\RR` and `\CC` ::
     843
     844            sage: Conic(CC, [1, 2, 3]).rational_point()
     845            (0 : 1.22474487139159*I : 1)
     846
     847            sage: Conic(RR, [1, 1, 1]).rational_point()
     848            Traceback (most recent call last):
     849            ...
     850            ValueError: Conic Projective Conic Curve over Real Field with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision!
     851        """
     852        bl,pt = self.has_rational_point(point = True, algorithm = algorithm,
     853                                        read_cache = read_cache)
     854        if bl:
     855            return pt
     856        raise ValueError, "Conic %s has no rational points over %s!" % \
     857                          (self, self.ambient_space().base_ring())
     858
     859
     860    def singular_point(self):
     861        r"""
     862        Returns a singular rational point of ``self``
     863       
     864        EXAMPLES:
     865       
     866        ::
     867
     868            sage: Conic(GF(2), [1,1,1,1,1,1]).singular_point()
     869            (1 : 1 : 1)
     870
     871        ``ValueError`` is raised if the conic has no rational singular point
     872           
     873        ::
     874
     875            sage: Conic(QQ, [1,1,1,1,1,1]).singular_point()
     876            Traceback (most recent call last):
     877            ...
     878            ValueError: The conic self (= Projective Conic Curve over Rational Field defined by x^2 + x*y + y^2 + x*z + y*z + z^2) has no rational singular point
     879        """
     880        b = self.has_singular_point(point = True)
     881        if not b[0]:
     882            raise ValueError, "The conic self (= %s) has no rational " \
     883                              "singular point" % self
     884        return b[1]
     885
     886    def symmetric_matrix(self):
     887        r"""
     888        The symmetric matrix `M` such that `(x y z) M (x y z)^t`
     889        is the defining equation of ``self``.
     890       
     891        EXAMPLES ::
     892       
     893            sage: R.<x, y, z> = QQ[]
     894            sage: C = Conic(x^2 + x*y/2 + y^2 + z^2)
     895            sage: C.symmetric_matrix()
     896            [  1 1/4   0]
     897            [1/4   1   0]
     898            [  0   0   1]
     899
     900            sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
     901            sage: v = vector([x, y, z])
     902            sage: v * C.symmetric_matrix() * v
     903            x^2 + 2*x*y + y^2 + 3*x*z + z^2
     904        """
     905        [a,b,c,d,e,f] = self.coefficients()
     906        if self.base_ring().characteristic() == 2:
     907            if b == 0 and c == 0 and e == 0:
     908                return matrix([[a,0,0],[0,d,0],[0,0,f]])
     909            raise ValueError, "The conic self (= %s) has no symmetric matrix " \
     910                              "because the base field has characteristic 2" % \
     911                              self
     912        from sage.matrix.constructor import matrix
     913        return matrix([[  a , b/2, c/2 ],
     914                       [ b/2,  d , e/2 ],
     915                       [ c/2, e/2,  f  ]])
     916
     917
     918    def upper_triangular_matrix(self):
     919        r"""
     920        The upper-triangular matrix `M` such that `(x y z) M (x y z)^t`
     921        is the defining equation of ``self``.
     922
     923        EXAMPLES::
     924
     925            sage: R.<x, y, z> = QQ[]
     926            sage: C = Conic(x^2 + x*y + y^2 + z^2)
     927            sage: C.upper_triangular_matrix()
     928            [1 1 0]
     929            [0 1 0]
     930            [0 0 1]
     931
     932            sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
     933            sage: v = vector([x, y, z])
     934            sage: v * C.upper_triangular_matrix() * v
     935            x^2 + 2*x*y + y^2 + 3*x*z + z^2
     936        """
     937        from sage.matrix.constructor import matrix
     938        [a,b,c,d,e,f] = self.coefficients()
     939        return matrix([[ a, b, c ],
     940                       [ 0, d, e ],
     941                       [ 0, 0, f ]])
     942   
     943    def variable_names(self):
     944        r"""
     945        Returns the variable names of the defining polynomial
     946        of ``self``.
     947
     948        EXAMPLES:
     949
     950        ::
     951
     952            sage: c=Conic([1,1,0,1,0,1], 'x,y,z')
     953            sage: c.variable_names()
     954            ('x', 'y', 'z')
     955            sage: c.variable_name()
     956            'x'
     957           
     958        The function ``variable_names()`` is required
     959        for the following construction:
     960       
     961        ::
     962       
     963            sage: C.<p,q,r> = Conic(QQ, [1, 1, 1])
     964            sage: C
     965            Projective Conic Curve over Rational Field defined by p^2 + q^2 + r^2
     966
     967        """
     968        return self.defining_polynomial().parent().variable_names()
     969   
     970       
  • new file sage/schemes/plane_conics/con_finite_field.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/con_finite_field.py
    - +  
     1r"""
     2Projective plane conics over finite fields.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-07-20)
     7
     8"""
     9#*****************************************************************************
     10#       Copyright (C) 2009/2010 Marco Streng <marco.streng@gmail.com>
     11#
     12#  Distributed under the terms of the GNU General Public License (GPL)
     13#
     14#    This code is distributed in the hope that it will be useful,
     15#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17#    General Public License for more details.
     18#
     19#  The full text of the GPL is available at:
     20#
     21#                  http://www.gnu.org/licenses/
     22#*****************************************************************************
     23
     24from sage.rings.all import PolynomialRing
     25from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_finite_field
     26from con_field import ProjectiveConic_field
     27
     28class ProjectiveConic_finite_field(ProjectiveConic_field, ProjectiveCurve_finite_field):
     29    r"""
     30    Create a projective plane conic curve over a finite field.
     31    See ``Conic`` for full documentation.
     32   
     33    EXAMPLES::
     34   
     35        sage: K.<a> = FiniteField(9, 'a')
     36        sage: P.<X, Y, Z> = K[]
     37        sage: Conic(X^2 + Y^2 - a*Z^2)
     38        Projective Conic Curve over Finite Field in a of size 3^2 defined by X^2 + Y^2 + (-a)*Z^2
     39       
     40    TESTS::
     41   
     42        sage: K.<a> = FiniteField(4, 'a')
     43        sage: Conic([a, 1, -1])._test_pickling()
     44    """
     45    def __init__(self, A, f):
     46        r"""
     47        See ``Conic`` for full documentation.
     48
     49        EXAMPLES ::
     50
     51            sage: Conic([GF(3)(1), 1, 1])
     52            Projective Conic Curve over Finite Field of size 3 defined by x^2 + y^2 + z^2
     53        """
     54        ProjectiveConic_field.__init__(self, A, f)
     55
     56
     57    def count_points(self, n):
     58        r"""
     59        If the base field `B` of `self` is finite of order `q`,
     60        then returns the number of points over `\GF{q}, ..., \GF{q^n}`.
     61       
     62        EXAMPLES::
     63
     64            sage: P.<x,y,z> = GF(3)[]
     65            sage: c = Curve(x^2+y^2+z^2); c
     66            Projective Conic Curve over Finite Field of size 3 defined by x^2 + y^2 + z^2
     67            sage: c.count_points(4)
     68            [4, 10, 28, 82]
     69        """       
     70        F = self.base_ring()
     71        q = F.cardinality()
     72        return [q**i+1 for i in range(1, n+1)]
     73       
     74       
     75    def has_rational_point(self, point = False, read_cache = True, \
     76                           algorithm = 'default'):
     77        r"""
     78        Always returns ``True`` because self has a point defined over
     79        its finite base field `B`.
     80
     81        If ``point`` is True, then returns a second output `S`, which is a
     82        rational point if one exists.
     83       
     84        Points are cached. If ``read_cache`` is True, then cached information
     85        is used for the output if available. If no cached point is available
     86        or ``read_cache`` is False, then random `y`-coordinates are tried
     87        if ``self`` is smooth and a singular point is returned otherwise.
     88       
     89        EXAMPLES ::
     90
     91            sage: Conic(FiniteField(37), [1, 2, 3, 4, 5, 6]).has_rational_point()
     92            True
     93           
     94            sage: C = Conic(FiniteField(2), [1, 1, 1, 1, 1, 0]); C
     95            Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z
     96            sage: C.has_rational_point(point = True)  # output is random
     97            (True, (0 : 0 : 1))
     98           
     99            sage: p = next_prime(10^50)
     100            sage: F = FiniteField(p)
     101            sage: C = Conic(F, [1, 2, 3]); C
     102            Projective Conic Curve over Finite Field of size 100000000000000000000000000000000000000000000000151 defined by x^2 + 2*y^2 + 3*z^2
     103            sage: C.has_rational_point(point = True)  # output is random
     104            (True,
     105             (14971942941468509742682168602989039212496867586852 : 75235465708017792892762202088174741054630437326388 : 1)
     106     
     107            sage: F.<a> = FiniteField(7^20)
     108            sage: C = Conic([1, a, -5]); C
     109            Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + (a)*y^2 + 2*z^2
     110            sage: C.has_rational_point(point = True)  # output is random
     111            (True,
     112             (a^18 + 2*a^17 + 4*a^16 + 6*a^13 + a^12 + 6*a^11 + 3*a^10 + 4*a^9 + 2*a^8 + 4*a^7 + a^6 + 4*a^4 + 6*a^2 + 3*a + 6 : 5*a^19 + 5*a^18 + 5*a^17 + a^16 + 2*a^15 + 3*a^14 + 4*a^13 + 5*a^12 + a^11 + 3*a^10 + 2*a^8 + 3*a^7 + 4*a^6 + 4*a^5 + 6*a^3 + 5*a^2 + 2*a + 4 : 1))
     113             
     114        TESTS ::
     115       
     116            sage: l = Sequence(cartesian_product_iterator([[0, 1] for i in range(6)]))
     117            sage: bigF = GF(next_prime(2^100))
     118            sage: bigF2 = GF(next_prime(2^50)^2, 'b')
     119            sage: m = [[F(b) for b in a] for a in l for F in [GF(2), GF(4, 'a'), GF(5), GF(9, 'a'), bigF, bigF2]]
     120            sage: m += [[F.random_element() for i in range(6)] for j in range(20) for F in [GF(5), bigF]]
     121            sage: c = [Conic(a) for a in m if a != [0,0,0,0,0,0]]
     122            sage: assert all([C.has_rational_point() for C in c])
     123            sage: r = randrange(0, 5)
     124            sage: assert all([C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c[r::5]]) # long time: 1.6 seconds
     125        """
     126        if not point:
     127            return True
     128        if read_cache:
     129            if self._rational_point is not None:
     130                return True, self._rational_point
     131        B = self.base_ring()
     132        s, pt = self.has_singular_point(point = True)
     133        if s:
     134            return True, pt
     135        while True:
     136            x = B.random_element()
     137            Y = PolynomialRing(B,'Y').gen()
     138            r = self.defining_polynomial()([x,Y,1]).roots()
     139            if len(r) > 0:
     140                return True, self.point([x,r[0][0],B(1)])
     141
     142
     143
  • new file sage/schemes/plane_conics/con_number_field.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/con_number_field.py
    - +  
     1r"""
     2Projective plane conics over a number field.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-07-20)
     7
     8"""
     9#*****************************************************************************
     10#       Copyright (C) 2009/2010 Marco Streng <marco.streng@gmail.com>
     11#
     12#  Distributed under the terms of the GNU General Public License (GPL)
     13#
     14#    This code is distributed in the hope that it will be useful,
     15#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17#    General Public License for more details.
     18#
     19#  The full text of the GPL is available at:
     20#
     21#                  http://www.gnu.org/licenses/
     22#*****************************************************************************
     23
     24from sage.rings.all import (is_RationalField, is_RealField,
     25                            is_RingHomomorphism, is_RealIntervalField,
     26                            is_ComplexField, is_ComplexIntervalField,
     27                            RDF, CDF, AA, QQbar, PolynomialRing)
     28
     29from sage.rings.number_field.number_field import is_NumberField                           
     30from sage.modules.free_module_element import vector
     31from con_field import ProjectiveConic_field
     32
     33class ProjectiveConic_number_field(ProjectiveConic_field):
     34    r"""
     35    Create a projective plane conic curve over a number field.
     36    See ``Conic`` for full documentation.
     37   
     38    EXAMPLES::
     39   
     40        sage: K.<a> = NumberField(x^3 - 2, 'a')
     41        sage: P.<X, Y, Z> = K[]
     42        sage: Conic(X^2 + Y^2 - a*Z^2)
     43        Projective Conic Curve over Number Field in a with defining polynomial x^3 - 2 defined by X^2 + Y^2 + (-a)*Z^2
     44       
     45    TESTS::
     46   
     47        sage: K.<a> = NumberField(x^3 - 3, 'a')
     48        sage: Conic([a, 1, -1])._test_pickling()
     49    """
     50    def __init__(self, A, f):
     51        r"""
     52        See ``Conic`` for full documentation.
     53
     54        EXAMPLES ::
     55
     56            sage: Conic([1, 1, 1])
     57            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     58        """
     59        ProjectiveConic_field.__init__(self, A, f)
     60        # a single prime such that self has no point over the completion
     61        self._local_obstruction = None
     62        # all finite primes such that self has no point over the completion
     63        self._finite_obstructions = None
     64        # all infinite primes such that self has no point over the completion
     65        self._infinite_obstructions = None
     66
     67
     68    def has_rational_point(self, point = False, obstruction = False,
     69                           algorithm = 'default', read_cache = True):
     70        r"""
     71        Returns ``True`` if and only if ``self`` has a point
     72        defined over its base field `B`.
     73
     74        If ``point`` and ``obstruction`` are both False (default),
     75        then the output is a boolean ``out`` saying whether ``self``
     76        has a rational point.
     77
     78        If ``point`` or ``obstruction`` is True, then the output is
     79        a pair ``(out, S)``, where ``out`` is as above and:
     80
     81         - if ``point`` is True and ``self`` has a rational point,
     82           then ``S`` is a rational point,
     83
     84         - if ``obstruction`` is True, ``self`` has no rational point,
     85           then ``S`` is a prime or infinite place of `B` such that no
     86           rational point exists over the completion at ``S``.
     87
     88        Points and obstructions are cached whenever they are found.
     89        Cached information is used for the output if available, but only
     90        if ``read_cache`` is True.
     91       
     92        ALGORITHM:
     93           
     94        The parameter ``algorithm``
     95        specifies the algorithm to be used:
     96           
     97         - ``'rnfisnorm'`` -- Use PARI's rnfisnorm
     98           (cannot be combined with ``obstruction = True``)
     99
     100         - ``'local'`` -- Check if a local solution exists for all primes
     101           and infinite places of `B` and apply the Hasse principle
     102           (cannot be combined with ``point = True``)
     103         
     104         - ``'default'`` -- Use ``'local'`` first.
     105           If a rational point exists, then use ``'rnfisnorm'``
     106           to find one.
     107           
     108        EXAMPLES:
     109       
     110        An example over `\QQ` ::
     111
     112            sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])
     113            sage: C.has_rational_point(point = True)
     114            (True, (-76842858034579/5424 : -5316144401/5424 : 1))
     115            sage: C.has_rational_point(algorithm = 'local', read_cache = False)
     116            True
     117
     118        Examples over number fields ::
     119           
     120            sage: K.<i> = QuadraticField(-1)
     121            sage: C = Conic(K, [1, 3, -5])
     122            sage: C.has_rational_point(point = True, obstruction = True)
     123            False, some prime ideal
     124            sage: C.has_rational_point(algorithm = "rnfisnorm")
     125            False
     126            sage: C.has_rational_point(algorithm = "rnfisnorm", obstruction = True)
     127            Traceback (most recent call last):
     128            ...
     129            ValueError: Algorithm rnfisnorm cannot be combined with obstruction = True in has_rational_point
     130           
     131            sage: P.<x> = QQ[]
     132            sage: L.<b> = NumberField(x^3-5)
     133            sage: C = Conic(L, [1, 2, -3])
     134            sage: C.has_rational_point(point = True, algorithm = 'rnfisnorm')
     135            (True, (5/3 : -1/3 : 1))
     136       
     137        TESTS:
     138       
     139        Create a bunch of conics over number fields and check if ``has_rational_point``
     140        runs without errors for ``algorithm = 'rnfisnorm'``. Check if all points
     141        returned are valid. ::
     142
     143            sage: P.<X> = QQ[]
     144            sage: Q = P.fraction_field()
     145            sage: c = [1, X/2, 1/X]
     146            sage: l = Sequence(cartesian_product_iterator([c for i in range(3)]))
     147            sage: l = l + [[X, 1, 1, 1, 1, 1]] + [[X, 1/5, 1, 1, 2, 1]]
     148            sage: K.<a> = QuadraticField(-23)
     149            sage: L.<b> = QuadraticField(19)
     150            sage: M.<c> = NumberField(X^3+3*X+1)
     151            sage: m = [[Q(b)(F.gen()) for b in a] for a in l for F in [K, L, M]]
     152            sage: d = []
     153            sage: c = []
     154            sage: c = [Conic(a) for a in m if a != [0,0,0]] # long time: 1 second
     155            sage: d = [C.has_rational_point(algorithm = 'rnfisnorm', point = True) for C in c] # long time: 15 seconds
     156            sage: assert all([c[k].defining_polynomial()(Sequence(d[k][1])) == 0 for k in range(len(c)) if d[k][0]])
     157
     158        Create a bunch of conics that are known to have rational points
     159        already over `\QQ` and check if points are found by
     160        ``has_rational_point``. ::
     161
     162            sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(3)]))
     163            sage: K.<a> = QuadraticField(-23)
     164            sage: L.<b> = QuadraticField(19)
     165            sage: M.<c> = NumberField(x^5+3*x+1)
     166            sage: m = [[F(b) for b in a] for a in l for F in [K, L, M]]
     167            sage: c = [Conic(a) for a in m if a != [0,0,0] and a != [1,1,1] and a != [-1,-1,-1]] # long time 0.4 seconds
     168            sage: assert all([C.has_rational_point(algorithm = 'rnfisnorm') for C in c]) # long time: 3.5 seconds
     169            sage: assert all([C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c]) # uses cache, long time if previous line isn't run
     170        """
     171        if read_cache:
     172            if self._rational_point is not None:
     173                if point or obstruction:
     174                    return True, self._rational_point
     175                else:
     176                    return True
     177            if self._local_obstruction is not None:
     178                if point or obstruction:
     179                    return False, self._local_obstruction
     180                else:
     181                    return False
     182            if (not point) and self._finite_obstructions == [] and \
     183               self._infinite_obstructions == []:
     184                if obstruction:
     185                    return True, None
     186                return True
     187        if self.has_singular_point():
     188            if point:
     189                return self.has_singular_point(point = True)
     190            if obstruction:
     191                return True, None
     192            return True
     193        B = self.base_ring()
     194        if algorithm == 'default':
     195            ret = self.has_rational_point(point = False, obstruction = True,
     196                                          algorithm = 'local')
     197            if ret[0]:
     198                if point:
     199                    ret = self.has_rational_point(point = True,
     200                                                  obstruction = False,
     201                                                  algorithm = 'rnfisnorm')
     202                    if not ret[0]:
     203                        raise RuntimeError, "Outputs of algorithms in " \
     204                                            "has_rational_point disagree for " \
     205                                            "conic %s" % self
     206                    return ret
     207                if obstruction:
     208                    return True, None
     209                return True
     210            if point or obstruction:
     211                return ret
     212            return False
     213        if algorithm == 'local':
     214            if point:
     215                raise ValueError, "Algorithm 'local' cannot be combined with " \
     216                                  "point = True in has_rational_point"
     217            obs = self.local_obstructions(infinite = True, finite = False,
     218                                          read_cache = read_cache)
     219            if obs != []:
     220                if obstruction:
     221                    return False, obs[0]
     222                return False
     223            obs = self.local_obstructions(read_cache = read_cache)
     224            if obs == []:
     225                if obstruction:
     226                    return True, None
     227                return True
     228            if obstruction:
     229                return False, obs[0]
     230            return False
     231        if algorithm == 'rnfisnorm':
     232            if obstruction:
     233                raise ValueError, "Algorithm rnfisnorm cannot be combined with " \
     234                                  "obstruction = True in has_rational_point"
     235            D, T = self.diagonal_matrix()
     236            abc = [D[0,0], D[1,1], D[2,2]]
     237            for j in range(3):
     238                if abc[j] == 0:
     239                    pt = self.point(T*vector({2:0,j:1}))
     240                    if point or obstruction:
     241                        return True, pt
     242                    return True
     243            if (-abc[1]/abc[0]).is_square():
     244                pt = self.point(T*vector([(-abc[1]/abc[0]).sqrt(), 1, 0]))
     245                if point or obstruction:
     246                    return True, pt
     247                return True
     248            if is_RationalField(B):
     249                K = B
     250                [KtoB, BtoK] = [K.hom(K) for i in range(2)]
     251            else:
     252                K = B.absolute_field('Y')
     253                [KtoB, BtoK] = K.structure()
     254            X = PolynomialRing(K).gen()
     255            L = K.extension(X^2+abc[2]/abc[0])
     256            isnorm = BtoK(-abc[1]/abc[0]).is_norm(L, element = True)
     257            if isnorm[0]:
     258                pt = self.point(T*vector([KtoB(isnorm[1][0]),
     259                                          KtoB(isnorm[1][1]), 1]))
     260                if point:
     261                    return True, pt
     262                return True
     263            if point:
     264                return False, None
     265            return False       
     266        if algorithm == 'qfsolve':
     267            raise TypeError, "Algorithm qfsolve in has_rational_point only " \
     268                                 "for conics over QQ, not over %s" % B
     269        raise ValueError, "Unknown algorithm %s in has_rational_point for %s" \
     270                          % algorithm, self
     271
     272    def is_locally_solvable(self, p):
     273        r"""
     274        Returns ``True`` if and only if ``self`` has a solution over the
     275        completion of the base field `B` of ``self`` at ``p``. Here ``p``
     276        is a finite prime or infinite place of `B`.
     277
     278        EXAMPLES::
     279
     280            sage: P.<x> = QQ[]
     281            sage: K.<a> = NumberField(x^3 + 5)
     282            sage: C = Conic(K, [1, 2, 3 - a])
     283            sage: [p1, p2] = K.places()
     284            sage: C.is_locally_solvable(p1)
     285            False
     286
     287            sage: C.is_locally_solvable(p2)
     288            True
     289
     290            sage: O = K.maximal_order()
     291            sage: f = (2*O).factor(); f
     292            (Fractional ideal (-a^2 - a + 1)) * (Fractional ideal (a^2 - 2*a + 3))
     293            sage: C.is_locally_solvable(f[0][0])
     294            True
     295
     296            sage: C.is_locally_solvable(f[1][0])
     297            False
     298        """
     299        D, T = self.diagonal_matrix()
     300        abc = [D[j, j] for j in range(3)]
     301        for a in abc:
     302            if a == 0:
     303                return True
     304
     305        a = -abc[0]/abc[2]
     306        b = -abc[1]/abc[2]
     307
     308        ret = self.base_ring().hilbert_symbol(a, b, p)
     309
     310        if ret == -1:
     311            if self._local_obstruction == None:
     312                if (not is_RingHomomorphism(p)) or p.codomain() == AA:
     313                    self._local_obstruction = p
     314            return False
     315
     316        return True
     317       
     318
     319    def local_obstructions(self, finite = True, infinite = True, read_cache = True):
     320        r"""
     321        Returns the sequence of finite primes and/or infinite places
     322        such that ``self`` is locally solvable at those primes and places.
     323       
     324        If the base field is `\QQ`, then the infinite place is denoted `-1`.
     325
     326        The parameters ``finite`` and ``infinite`` (both True by default) are
     327        used to specify whether to look at finite and/or infinite places.
     328        Note that ``finite = True`` involves factorization of the determinant
     329        of ``self``, hence may be slow.
     330       
     331        Local obstructions are cached. The parameter ``read_cache``
     332        specifies whether to look at the cache before computing anything.
     333
     334        EXAMPLES ::
     335
     336            sage: K.<i> = QuadraticField(-1)
     337            sage: Conic(K, [1, 2, 3]).local_obstructions()
     338            []
     339           
     340            sage: L.<a> = QuadraticField(5)
     341            sage: Conic(L, [1, 2, 3]).local_obstructions()
     342            [Ring morphism:
     343              From: Number Field in a with defining polynomial x^2 - 5
     344              To:   Algebraic Real Field
     345              Defn: a |--> -2.236067977499790?, Ring morphism:
     346              From: Number Field in a with defining polynomial x^2 - 5
     347              To:   Algebraic Real Field
     348              Defn: a |--> 2.236067977499790?]
     349
     350           
     351        """
     352        obs0 = []
     353        obs1 = []
     354        B = self.base_ring()
     355        if infinite:
     356            if read_cache and self._infinite_obstructions != None:
     357                obs0 = self._infinite_obstructions
     358            else:
     359                for b in B.embeddings(AA):
     360                    if not self.is_locally_solvable(b):
     361                        obs0.append(b)
     362                self._infinite_obstructions = obs0
     363        if finite:
     364            if read_cache and self._finite_obstructions != None:
     365                obs1 = self._finite_obstructions
     366            else:
     367                candidates = []
     368                if self.determinant() != 0:
     369                    O = B.maximal_order()
     370                    for a in self.symmetric_matrix().list():
     371                        if a != 0:
     372                            for f in O.fractional_ideal(a).factor():
     373                                if f[1] < 0 and not f[0] in candidates:
     374                                    candidates.append(f[0])
     375                    for f in O.fractional_ideal(2*self.determinant()).factor():
     376                        if f[1] > 0 and not f[0] in candidates:
     377                            candidates.append(f[0])       
     378                for b in candidates:
     379                    if not self.is_locally_solvable(b):
     380                       obs1.append(b)
     381                self._infinite_obstructions = obs1
     382        obs = obs1 + obs0
     383        if finite and infinite:
     384            assert len(obs) % 2 == 0
     385        return obs
     386
     387
  • new file sage/schemes/plane_conics/con_prime_finite_field.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/con_prime_finite_field.py
    - +  
     1r"""
     2Projective plane conics over prime finite fields.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-07-20)
     7
     8
     9"""
     10#*****************************************************************************
     11#       Copyright (C) 2010 Marco Streng <marco.streng@gmail.com>
     12#
     13#  Distributed under the terms of the GNU General Public License (GPL)
     14#
     15#    This code is distributed in the hope that it will be useful,
     16#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     17#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18#    General Public License for more details.
     19#
     20#  The full text of the GPL is available at:
     21#
     22#                  http://www.gnu.org/licenses/
     23#*****************************************************************************
     24
     25from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_prime_finite_field
     26from con_finite_field import ProjectiveConic_finite_field
     27
     28class ProjectiveConic_prime_finite_field(ProjectiveConic_finite_field, ProjectiveCurve_prime_finite_field):
     29    r"""
     30    Create a projective plane conic curve over a prime finite field.
     31    See ``Conic`` for full documentation.
     32   
     33    EXAMPLES::
     34   
     35        sage: P.<X, Y, Z> = FiniteField(5)[]
     36        sage: Conic(X^2 + Y^2 - 2*Z^2)
     37        Projective Conic Curve over Finite Field of size 5 defined by X^2 + Y^2 - 2*Z^2
     38 
     39    TESTS::
     40   
     41        sage: Conic([FiniteField(7)(1), 1, -1])._test_pickling()
     42    """
     43    def __init__(self, A, f):
     44        r"""
     45        See ``Conic`` for full documentation.
     46
     47        EXAMPLES ::
     48
     49            sage: Conic([GF(3)(1), 1, 1])
     50            Projective Conic Curve over Finite Field of size 3 defined by x^2 + y^2 + z^2
     51        """
     52        ProjectiveConic_finite_field.__init__(self, A, f)
     53        ProjectiveCurve_prime_finite_field.__init__(self, A, f)
     54
     55
  • new file sage/schemes/plane_conics/con_rational_field.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/con_rational_field.py
    - +  
     1r"""
     2Projective plane conics over `\QQ`.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-07-20)
     7
     8- Nick Alexander (2008-01-08)
     9
     10"""
     11#*****************************************************************************
     12#       Copyright (C) 2008 Nick Alexander <ncalexander@gmail.com>
     13#       Copyright (C) 2009/2010 Marco Streng <marco.streng@gmail.com>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#
     17#    This code is distributed in the hope that it will be useful,
     18#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     19#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     20#    General Public License for more details.
     21#
     22#  The full text of the GPL is available at:
     23#
     24#                  http://www.gnu.org/licenses/
     25#*****************************************************************************
     26
     27from sage.rings.all import (PolynomialRing, ZZ, QQ,
     28                            is_RealField, is_RingHomomorphism)
     29from sage.structure.sequence import Sequence
     30from sage.schemes.generic.projective_space import ProjectiveSpace
     31from sage.matrix.constructor import Matrix
     32
     33from sage.quadratic_forms.qfsolve import qfsolve, qfparam
     34
     35from con_number_field import ProjectiveConic_number_field
     36
     37from sage.structure.element import is_InfinityElement
     38
     39from sage.rings.arith import (lcm, hilbert_symbol)
     40
     41class ProjectiveConic_rational_field(ProjectiveConic_number_field):
     42    r"""
     43    Create a projective plane conic curve over `\QQ`.
     44    See ``Conic`` for full documentation.
     45   
     46    EXAMPLES::
     47   
     48        sage: P.<X, Y, Z> = QQ[]
     49        sage: Conic(X^2 + Y^2 - 3*Z^2)
     50        Projective Conic Curve over Rational Field defined by X^2 + Y^2 - 3*Z^2
     51       
     52    TESTS::
     53   
     54        sage: Conic([2, 1, -1])._test_pickling()
     55    """
     56    def __init__(self, A, f):
     57        r"""
     58        See ``Conic`` for full documentation.
     59
     60        EXAMPLES::
     61       
     62            sage: Conic([1, 1, 1])
     63            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     64        """
     65        ProjectiveConic_number_field.__init__(self, A, f)
     66
     67
     68    def has_rational_point(self, point = False, obstruction = False,
     69                           algorithm = 'default', read_cache = True):
     70        r"""
     71        Returns True if and only if ``self`` has a point defined over `\QQ`.
     72
     73        If ``point`` and ``obstruction`` are both False (default), then
     74        the output is a boolean ``out`` saying whether ``self`` has a
     75        rational point.
     76
     77        If ``point`` or ``obstruction`` is True, then the output is
     78        a pair ``(out, S)``, where ``out`` is as above and the following
     79        holds:
     80       
     81         - if ``point`` is True and ``self`` has a rational point,
     82           then ``S`` is a rational point,
     83
     84         - if ``obstruction`` is True and ``self`` has no rational point,
     85           then ``S`` is a prime such that no rational point exists
     86           over the completion at ``S`` or `-1` if no point exists over `\RR`.
     87       
     88        Points and obstructions are cached, whenever they are found.
     89        Cached information is used if and only if ``read_cache`` is True.
     90       
     91        ALGORITHM:
     92           
     93        The parameter ``algorithm``
     94        specifies the algorithm to be used:
     95           
     96         - ``'qfsolve'`` -- Use Denis Simon's pari script Qfsolve
     97           (see ``sage.quadratic_forms.qfsolve.qfsolve``)
     98
     99         - ``'rnfisnorm'`` -- Use PARI's function rnfisnorm
     100           (cannot be combined with ``obstruction = True``)
     101
     102         - ``'local'`` -- Check if a local solution exists for all primes
     103           and infinite places of `\QQ` and apply the Hasse principle
     104           (cannot be combined with ``point = True``)
     105
     106         - ``'default'`` -- Use ``'qfsolve'``
     107           
     108        EXAMPLES::
     109
     110            sage: C = Conic(QQ, [1, 2, -3])
     111            sage: C.has_rational_point(point = True)
     112            (True, (-1 : -1 : 1))
     113            sage: D = Conic(QQ, [1, 3, -5])
     114            sage: D.has_rational_point(point = True)
     115            (False, 3)
     116            sage: P.<X,Y,Z> = QQ[]
     117            sage: E = Curve(X^2 + Y^2 + Z^2); E
     118            Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2
     119            sage: E.has_rational_point(obstruction = True)
     120            (False, -1)
     121           
     122        The following would not terminate quickly with
     123        ``algorithm = 'rnfisnorm'`` ::
     124
     125            sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])
     126            sage: C.has_rational_point(point = True)
     127            (True, (-76842858034579/5424 : -5316144401/5424 : 1))
     128            sage: C.has_rational_point(algorithm = 'local', read_cache = False)
     129            True
     130
     131        TESTS:
     132       
     133        Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors
     134        and returns consistent answers for all algorithms. Check if all points returned are valid. ::
     135
     136            sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)]))
     137            sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)]
     138            sage: d = []
     139            sage: d = [[C]+[C.has_rational_point(algorithm = algorithm, read_cache = False, obstruction = (algorithm != 'rnfisnorm'), point = (algorithm != 'local')) for algorithm in ['local', 'qfsolve', 'rnfisnorm']] for C in c[::10]] # long time: 7 seconds
     140            sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d])
     141            sage: assert all([e[0].defining_polynomial()(Sequence(e[i][1])) == 0 for e in d for i in [2,3] if e[1][0]])
     142        """
     143        if read_cache:
     144            if self._rational_point is not None:
     145                if point or obstruction:
     146                    return True, self._rational_point
     147                else:
     148                    return True
     149            if self._local_obstruction is not None:
     150                if point or obstruction:
     151                    return False, self._local_obstruction
     152                else:
     153                    return False
     154            if (not point) and self._finite_obstructions == [] and \
     155               self._infinite_obstructions == []:
     156                if obstruction:
     157                    return True, None
     158                return True
     159        if self.has_singular_point():
     160            if point:
     161                return self.has_singular_point(point = True)
     162            if obstruction:
     163                return True, None
     164            return True
     165        if algorithm == 'default' or algorithm == 'qfsolve':
     166            M = self.symmetric_matrix()
     167            M *= lcm([ t.denominator() for t in M.list() ])
     168            pt = qfsolve(M)
     169            if pt in ZZ:
     170                if self._local_obstruction == None:
     171                    self._local_obstruction = pt
     172                if point or obstruction:
     173                    return False, pt
     174                return False
     175            pt = self.point([pt[0], pt[1], pt[2]])
     176            if point or obstruction:
     177                return True, pt
     178            return True
     179        ret = ProjectiveConic_number_field.has_rational_point( \
     180                                           self, point = point, \
     181                                           obstruction = obstruction, \
     182                                           algorithm = algorithm, \
     183                                           read_cache = read_cache)
     184        if point or obstruction:
     185            if is_RingHomomorphism(ret[1]):
     186                ret[1] = -1
     187        return ret
     188                                           
     189    def is_locally_solvable(self, p):
     190        r"""
     191        Returns True if and only if ``self`` has a solution over the
     192        `p`-adic numbers. Here `p` is a prime number or equals
     193        `-1`, infinity, or `\RR` to denote the infinite place.
     194
     195        EXAMPLES::
     196       
     197            sage: C = Conic(QQ, [1,2,3])
     198            sage: C.is_locally_solvable(-1)
     199            False
     200            sage: C.is_locally_solvable(2)
     201            False
     202            sage: C.is_locally_solvable(3)
     203            True
     204            sage: C.is_locally_solvable(QQ.hom(RR))
     205            False
     206            sage: D = Conic(QQ, [1, 2, -3])
     207            sage: D.is_locally_solvable(infinity)
     208            True
     209            sage: D.is_locally_solvable(RR)
     210            True           
     211
     212        """
     213        D, T = self.diagonal_matrix()
     214        abc = [D[j, j] for j in range(3)]
     215        if abc[2] == 0:
     216            return True
     217        a = -abc[0]/abc[2]
     218        b = -abc[1]/abc[2]
     219        if is_RealField(p) or is_InfinityElement(p):
     220            p = -1
     221        elif is_RingHomomorphism(p):
     222            if p.domain() is QQ and is_RealField(p.codomain()):
     223                p = -1
     224            else:
     225                raise TypeError, "p (=%s) needs to be a prime of base field " \
     226                                 "B ( =`QQ`) in is_locally_solvable" % p
     227        if hilbert_symbol(a, b, p) == -1:
     228            if self._local_obstruction == None:
     229                self._local_obstruction = p
     230            return False
     231        return True
     232
     233    def local_obstructions(self, finite = True, infinite = True, read_cache = True):
     234        r"""
     235        Returns the sequence of finite primes and/or infinite places
     236        such that self is locally solvable at those primes and places.
     237       
     238        The infinite place is denoted `-1`.
     239
     240        The parameters ``finite`` and ``infinite`` (both True by default) are
     241        used to specify whether to look at finite and/or infinite places.
     242        Note that ``finite = True`` involves factorization of the determinant
     243        of ``self``, hence may be slow.
     244       
     245        Local obstructions are cached. The parameter ``read_cache`` specifies
     246        whether to look at the cache before computing anything.
     247
     248        EXAMPLES ::
     249
     250            sage: Conic(QQ, [1, 1, 1]).local_obstructions()
     251            [2, -1]
     252            sage: Conic(QQ, [1, 2, -3]).local_obstructions()
     253            []
     254            sage: Conic(QQ, [1, 2, 3, 4, 5, 6]).local_obstructions()
     255            [41, -1]
     256           
     257        """
     258        obs0 = []
     259        obs1 = []
     260        if infinite:
     261            if read_cache and self._infinite_obstructions != None:
     262                obs0 = self._infinite_obstructions
     263            else:
     264                if not self.is_locally_solvable(-1):
     265                    obs0 = [-1]
     266                self._infinite_obstructions = obs0
     267        if finite:
     268            if read_cache and self._finite_obstructions != None:
     269                obs1 = self._finite_obstructions
     270            else:
     271                candidates = []
     272                if self.determinant() != 0:
     273                    for a in self.symmetric_matrix().list():
     274                        if a != 0:
     275                            for f in a.factor():
     276                                if f[1] < 0 and not f[0] in candidates:
     277                                    candidates.append(f[0])
     278                    for f in (2*self.determinant()).factor():
     279                        if f[1] > 0 and not f[0] in candidates:
     280                            candidates.append(f[0])
     281                for b in candidates:
     282                    if not self.is_locally_solvable(b):
     283                       obs1.append(b)
     284                self._infinite_obstructions = obs1
     285        obs = obs1 + obs0
     286        if finite and infinite:
     287            assert len(obs) % 2 == 0
     288        return obs
     289
     290    def parametrization(self, point=None, morphism=True):
     291        r"""
     292        Return a parametrization `f` of ``self`` together with the
     293        inverse of `f`.
     294
     295        If ``point`` is specified, then that point is used
     296        for the parametrization. Otherwise, use ``self.rational_point()``
     297        to find a point.
     298           
     299        If ``morphism`` is True, then `f` is returned in the form
     300        of a Scheme morphism. Otherwise, it is a tuple of polynomials
     301        that gives the parametrization.
     302       
     303        ALGORITHM:
     304       
     305        Uses Denis Simon's pari script Qfparam.
     306        See ``sage.quadratic_forms.qfsolve.qfparam``.
     307       
     308        EXAMPLES ::
     309
     310            sage: c = Conic([1,1,-1])
     311            sage: c.parametrization()
     312            (Scheme morphism:
     313              From: Projective Space of dimension 1 over Rational Field
     314              To:   Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
     315              Defn: Defined on coordinates by sending (x : y) to
     316                    (2*x*y : x^2 - y^2 : x^2 + y^2),
     317             Scheme morphism:
     318               From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
     319               To:   Projective Space of dimension 1 over Rational Field
     320               Defn: Defined on coordinates by sending (x : y : z) to
     321                     (1/2*x : -1/2*y + 1/2*z))
     322       
     323        An example with ``morphism = False`` ::
     324
     325            sage: R.<x,y,z> = QQ[]
     326            sage: C = Curve(7*x^2 + 2*y*z + z^2)
     327            sage: (p, i) = C.parametrization(morphism = False); (p, i)
     328            ([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])
     329            sage: C.defining_polynomial()(p)
     330            0
     331            sage: i[0](p) / i[1](p)
     332            x/y
     333           
     334        A ``ValueError`` is raised if ``self`` has no rational point ::
     335
     336            sage: C = Conic(x^2 + 2*y^2 + z^2)
     337            sage: C.parametrization()
     338            Traceback (most recent call last):
     339            ...
     340            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!
     341
     342        A ``ValueError`` is raised if ``self`` is not smooth ::
     343       
     344            sage: C = Conic(x^2 + y^2)
     345            sage: C.parametrization()
     346            Traceback (most recent call last):
     347            ...
     348            ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
     349        """
     350        if (not self._parametrization is None) and not point:
     351            par = self._parametrization
     352        else:
     353            if not self.is_smooth():
     354                raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self
     355            if point == None:
     356                point = self.rational_point()
     357            point = Sequence(point)
     358            Q = PolynomialRing(QQ, 'x,y')
     359            [x, y] = Q.gens()
     360            gens = self.ambient_space().gens()
     361            M = self.symmetric_matrix()
     362            M *= lcm([ t.denominator() for t in M.list() ])
     363            par1 = qfparam(M, point)
     364            B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])
     365            # self is in the image of B and does not lie on a line,
     366            # hence B is invertible
     367            A = B.inverse()
     368            par2 = [sum([A[i,j]*gens[j] for j in range(3)]) for i in [1,0]]
     369            par = ([Q(pol(x/y)*y**2) for pol in par1], par2)
     370            if self._parametrization is None:
     371                self._parametrization = par
     372        if not morphism:
     373            return par
     374        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
     375        return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
     376
  • new file sage/schemes/plane_conics/constructor.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_conics/constructor.py
    - +  
     1r"""
     2Plane conic constructor.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-07-20)
     7
     8- Nick Alexander (2008-01-08)
     9
     10"""
     11#*****************************************************************************
     12#       Copyright (C) 2008 Nick Alexander <ncalexander@gmail.com>
     13#       Copyright (C) 2009/2010 Marco Streng <marco.streng@gmail.com>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#
     17#    This code is distributed in the hope that it will be useful,
     18#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     19#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     20#    General Public License for more details.
     21#
     22#  The full text of the GPL is available at:
     23#
     24#                  http://www.gnu.org/licenses/
     25#*****************************************************************************
     26
     27from sage.matrix.constructor import Matrix
     28from sage.modules.free_module_element import vector
     29from sage.quadratic_forms.all import is_QuadraticForm
     30from sage.rings.all import (is_MPolynomial, PolynomialRing,
     31                            is_IntegralDomain, is_FiniteField,
     32                            is_PrimeFiniteField,
     33                            is_RationalField)
     34from sage.rings.number_field.number_field import is_NumberField                           
     35from sage.schemes.generic.all import ProjectiveSpace
     36from sage.schemes.generic.morphism import (SchemeMorphism_affine_coordinates,
     37                            SchemeMorphism_projective_coordinates_field)
     38from sage.structure.all import Sequence
     39from sage.structure.element import is_Matrix
     40
     41from con_field import ProjectiveConic_field
     42from con_finite_field import ProjectiveConic_finite_field
     43from con_prime_finite_field import ProjectiveConic_prime_finite_field
     44from con_number_field import ProjectiveConic_number_field
     45from con_rational_field import ProjectiveConic_rational_field
     46
     47def Conic(base_field, F=None, names=None, unique=True):
     48    r"""
     49    Return the plane projective conic curve defined by ``F``
     50    over ``base_field``.
     51   
     52    The input form ``Conic(F, names=None)`` is also accepted,
     53    in which case the fraction field of the base ring of ``F``
     54    is used as base field.
     55
     56    INPUT:
     57   
     58    - ``base_field`` -- The base field of the conic.
     59   
     60    - ``names`` -- a list, tuple, or comma separated string
     61      of three variable names specifying the names
     62      of the coordinate functions of the ambient
     63      space `\Bold{P}^3`. If not specified or read
     64      off from ``F``, then this defaults to ``'x,y,z'``.
     65
     66    - ``F`` -- a polynomial, list, matrix, ternary quadratic form,
     67      or list or tuple of 5 points in the plane.
     68                   
     69                   If ``F`` is a polynomial or quadratic form,
     70                   then the output is the curve in the projective plane
     71                   defined by ``F = 0``.
     72
     73                   If ``F`` is a polynomial, then it must be a polynomial
     74                   of degree at most 2 in 2 variables, or a homogeneous
     75                   polynomial in of degree 2 in 3 variables.
     76                   
     77                   If ``F`` is a matrix, then the output is the zero locus
     78                   of `(x,y,z) F (x,y,z)^t`.
     79   
     80                   If ``F`` is a list of coefficients, then it has
     81                   length 3 or 6 and gives the coefficients of
     82                   the monomials `x^2, y^2, z^2` or all 6 monomials
     83                   `x^2, xy, xz, y^2, yz, z^2` in lexicographic order.
     84
     85                   If ``F`` is a list of 5 points in the plane, then the output
     86                   is a conic through those points.
     87     
     88    - ``unique`` -- Used only if ``F`` is a list of points in the plane.
     89      If the conic through the points is not unique, then
     90      raise ``ValueError`` if and only if ``unique`` is True
     91                   
     92    OUTPUT:
     93   
     94    A plane projective conic curve defined by ``F`` over a field.
     95   
     96    EXAMPLES:
     97   
     98    Conic curves given by polynomials ::
     99
     100        sage: X,Y,Z = QQ['X,Y,Z'].gens()
     101        sage: Conic(X^2 - X*Y + Y^2 - Z^2)
     102        Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2
     103        sage: x,y = GF(7)['x,y'].gens()
     104        sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W')
     105        Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2
     106
     107    Conic curves given by matrices ::
     108
     109        sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z')
     110        Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2
     111
     112        sage: x,y,z = GF(11)['x,y,z'].gens()
     113        sage: C = Conic(x^2+y^2-2*z^2); C
     114        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
     115        sage: Conic(C.symmetric_matrix(), 'x,y,z')
     116        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
     117
     118    Conics given by coefficients ::
     119   
     120        sage: Conic(QQ, [1,2,3])
     121        Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2
     122        sage: Conic(GF(7), [1,2,3,4,5,6], 'X')
     123        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
     124   
     125    The conic through a set of points ::
     126
     127        sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C
     128        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
     129        sage: C.rational_point()
     130        (10 : 2 : 1)
     131        sage: C.point([3,4])
     132        (3 : 4 : 1)
     133
     134        sage: a=AffineSpace(GF(13),2)
     135        sage: Conic([a([x,x^2]) for x in range(5)])
     136        Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z
     137    """
     138    if not (is_IntegralDomain(base_field) or base_field == None):
     139        if names is None:
     140            names = F
     141        F = base_field
     142        base_field = None
     143    if isinstance(F, (list,tuple)):
     144        if len(F) == 1:
     145            return Conic(base_field, F[0], names)
     146        if names == None:
     147            names = 'x,y,z'
     148        if len(F) == 5:
     149            L=[]
     150            for f in F:
     151                if isinstance(f, SchemeMorphism_affine_coordinates):
     152                    C = Sequence(f, universe = base_field)
     153                    if len(C) != 2:
     154                        raise TypeError, "points in F (=%s) must be planar"%F
     155                    C.append(1)
     156                elif isinstance(f, SchemeMorphism_projective_coordinates_field):
     157                    C = Sequence(f, universe = base_field)
     158                elif isinstance(f, (list, tuple)):
     159                    C = Sequence(f, universe = base_field)
     160                    if len(C) == 2:
     161                        C.append(1)
     162                else:
     163                    raise TypeError, "F (=%s) must be a sequence of planar " \
     164                                      "points" % F
     165                if len(C) != 3:
     166                    raise TypeError, "points in F (=%s) must be planar" % F
     167                P = C.universe()
     168                if not is_IntegralDomain(P):
     169                    raise TypeError, "coordinates of points in F (=%s) must " \
     170                                     "be in an integral domain" % F
     171                L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2,
     172                                   C[1]*C[2], C[2]**2], P.fraction_field()))
     173            M=Matrix(L)
     174            if unique and M.rank() != 5:
     175                raise ValueError, "points in F (=%s) do not define a unique " \
     176                                   "conic" % F
     177            con = Conic(base_field, Sequence(M.right_kernel().gen()), names)
     178            con.point(F[0])
     179            return con
     180        F = Sequence(F, universe = base_field)
     181        base_field = F.universe().fraction_field()
     182        temp_ring = PolynomialRing(base_field, 3, names)
     183        (x,y,z) = temp_ring.gens()
     184        if len(F) == 3:
     185            return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2)
     186        if len(F) == 6:
     187            return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \
     188                         F[4]*y*z + F[5]*z**2)
     189        raise TypeError, "F (=%s) must be a sequence of 3 or 6" \
     190                         "coefficients" % F
     191    if is_QuadraticForm(F):
     192        F = F.matrix()
     193    if is_Matrix(F) and F.is_square() and F.ncols() == 3:
     194        if names == None:
     195            names = 'x,y,z'
     196        temp_ring = PolynomialRing(F.base_ring(), 3, names)
     197        F = vector(temp_ring.gens()) * F * vector(temp_ring.gens())
     198
     199    if not is_MPolynomial(F):
     200        raise TypeError, "F (=%s) must be a three-variable polynomial or " \
     201                         "a sequence of points or coefficients" % F
     202
     203    if F.total_degree() != 2:
     204        raise TypeError, "F (=%s) must have degree 2" % F
     205
     206    if base_field == None:
     207        base_field = F.base_ring()
     208    if not is_IntegralDomain(base_field):
     209        raise ValueError, "Base field (=%s) must be a field" % base_field
     210    base_field = base_field.fraction_field()
     211    if names == None:
     212        names = F.parent().variable_names()
     213    pol_ring = PolynomialRing(base_field, 3, names)
     214
     215    if F.parent().ngens() == 2:
     216        (x,y,z) = pol_ring.gens()
     217        F = pol_ring(F(x/z,y/z)*z**2)   
     218
     219    if F == 0:
     220        raise ValueError, "F must be nonzero over base field %s" % base_field
     221
     222    if F.total_degree() != 2:
     223        raise TypeError, "F (=%s) must have degree 2 over base field %s" % \
     224                          (F, base_field)
     225
     226    if F.parent().ngens() == 3:
     227        P2 = ProjectiveSpace(2, base_field, names)
     228        if is_PrimeFiniteField(base_field):
     229            return ProjectiveConic_prime_finite_field(P2, F)
     230        if is_FiniteField(base_field):
     231            return ProjectiveConic_finite_field(P2, F)
     232        if is_RationalField(base_field):
     233            return ProjectiveConic_rational_field(P2, F)
     234        if is_NumberField(base_field):
     235            return ProjectiveConic_number_field(P2, F)
     236        return ProjectiveConic_field(P2, F)
     237
     238    raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
  • sage/schemes/plane_curves/constructor.py

    diff -r 0bada77b22e6 -r bbbd71be40af sage/schemes/plane_curves/constructor.py
    a b  
    4242                          AffineCurve_finite_field,
    4343                          AffineCurve_prime_finite_field)
    4444
     45from sage.schemes.plane_conics.constructor import Conic
     46
    4547def Curve(F):
    4648    """
    4749    Return the plane or space curve defined by `F`, where
     
    101103   
    102104        sage: x,y,z = QQ['x,y,z'].gens()
    103105        sage: Curve((x-y)*(x+y))
    104         Projective Curve over Rational Field defined by x^2 - y^2
     106        Projective Conic Curve over Rational Field defined by x^2 - y^2
    105107        sage: Curve((x-y)^2*(x+y)^2)
    106108        Projective Curve over Rational Field defined by x^4 - 2*x^2*y^2 + y^4
    107109   
     
    144146   
    145147        sage: x,y,z = QQ['x,y,z'].gens()
    146148        sage: Curve(x^2+y^2)
    147         Projective Curve over Rational Field defined by x^2 + y^2
     149        Projective Conic Curve over Rational Field defined by x^2 + y^2
    148150        sage: Curve(x^2+y^2+z)
    149151        Traceback (most recent call last):
    150152        ...
     
    203205            raise ValueError, "defining polynomial of curve must be nonzero"
    204206        P2 = ProjectiveSpace(2, P.base_ring())
    205207        P2._coordinate_ring = P
     208       
     209        if F.total_degree() == 2 and k.is_field():
     210            return Conic(F)
     211       
    206212        if is_FiniteField(k):
    207213            if k.is_prime_field():
    208214                return ProjectiveCurve_prime_finite_field(P2, F)
  • setup.py

    diff -r 0bada77b22e6 -r bbbd71be40af setup.py
    a b  
    10141014                     'sage.schemes.generic',
    10151015                     'sage.schemes.jacobians',
    10161016                     'sage.schemes.plane_curves',
     1017                     'sage.schemes.plane_conics',
    10171018                     'sage.schemes.plane_quartics',
    10181019                     'sage.schemes.elliptic_curves',
    10191020                     'sage.schemes.hyperelliptic_curves',