Ticket #727: trac_727_conics_without_number_fields.patch

File trac_727_conics_without_number_fields.patch, 82.1 KB (added by Marco Streng, 12 years ago)

Apply only this latest file (works on sage 4.6.1.rc0 without any other patches)

  • doc/en/reference/plane_curves.rst

    # HG changeset patch
    # User Marco Streng <marco.streng@gmail.com>
    # Date 1294928351 0
    # Node ID 9f7d2c8e89e9fefefd235bbaba48dcb5c8e40823
    # Parent  c58f82863c75b2e53662e08cd550bb398653174c
    Trac 727: conics
    
    diff -r c58f82863c75 -r 9f7d2c8e89e9 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 c58f82863c75 -r 9f7d2c8e89e9 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        PARI/GP 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 c58f82863c75 -r 9f7d2c8e89e9 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 c58f82863c75 -r 9f7d2c8e89e9 sage/schemes/plane_conics/__init__.py
    - +  
     1
     2
  • new file sage/schemes/plane_conics/all.py

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

    diff -r c58f82863c75 -r 9f7d2c8e89e9 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 c58f82863c75 -r 9f7d2c8e89e9 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
     61        # a single prime such that self has no point over the completion
     62        self._local_obstruction = None
     63        # all finite primes such that self has no point over the completion
     64        self._finite_obstructions = None
     65        # all infinite primes such that self has no point over the completion
     66        self._infinite_obstructions = None
     67
     68
     69
  • new file sage/schemes/plane_conics/con_prime_finite_field.py

    diff -r c58f82863c75 -r 9f7d2c8e89e9 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 c58f82863c75 -r 9f7d2c8e89e9 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         - ``'local'`` -- Check if a local solution exists for all primes
     100           and infinite places of `\QQ` and apply the Hasse principle
     101           (cannot be combined with ``point = True``)
     102
     103         - ``'default'`` -- Use ``'qfsolve'``
     104           
     105        EXAMPLES::
     106
     107            sage: C = Conic(QQ, [1, 2, -3])
     108            sage: C.has_rational_point(point = True)
     109            (True, (1 : 1 : 1))
     110            sage: D = Conic(QQ, [1, 3, -5])
     111            sage: D.has_rational_point(point = True)
     112            (False, 3)
     113            sage: P.<X,Y,Z> = QQ[]
     114            sage: E = Curve(X^2 + Y^2 + Z^2); E
     115            Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2
     116            sage: E.has_rational_point(obstruction = True)
     117            (False, -1)
     118           
     119        A very big example ::
     120
     121            sage: C = Conic(QQ, [1, 113922743, -310146482690273725409])
     122            sage: C.has_rational_point(point = True)
     123            (True, (-76842858034579/5424 : -5316144401/5424 : 1))
     124            sage: C.has_rational_point(algorithm = 'local', read_cache = False)
     125            True
     126
     127        TESTS:
     128       
     129        Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors
     130        and returns consistent answers for all algorithms. Check if all points returned are valid. ::
     131
     132            sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)]))
     133            sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)]
     134            sage: d = []
     135            sage: d = [[C]+[C.has_rational_point(algorithm = algorithm, read_cache = False, obstruction = True, point = (algorithm != 'local')) for algorithm in ['local', 'qfsolve']] for C in c[::10]] # long time: 7 seconds
     136            sage: assert all([e[1][0] == e[2][0] for e in d])
     137            sage: assert all([e[0].defining_polynomial()(Sequence(e[2][1])) == 0 for e in d if e[1][0]])
     138        """
     139        if read_cache:
     140            if self._rational_point is not None:
     141                if point or obstruction:
     142                    return True, self._rational_point
     143                else:
     144                    return True
     145            if self._local_obstruction is not None:
     146                if point or obstruction:
     147                    return False, self._local_obstruction
     148                else:
     149                    return False
     150            if (not point) and self._finite_obstructions == [] and \
     151               self._infinite_obstructions == []:
     152                if obstruction:
     153                    return True, None
     154                return True
     155        if self.has_singular_point():
     156            if point:
     157                return self.has_singular_point(point = True)
     158            if obstruction:
     159                return True, None
     160            return True
     161        if algorithm == 'default' or algorithm == 'qfsolve':
     162            M = self.symmetric_matrix()
     163            M *= lcm([ t.denominator() for t in M.list() ])
     164            pt = qfsolve(M)
     165            if pt in ZZ:
     166                if self._local_obstruction == None:
     167                    self._local_obstruction = pt
     168                if point or obstruction:
     169                    return False, pt
     170                return False
     171            pt = self.point([pt[0], pt[1], pt[2]])
     172            if point or obstruction:
     173                return True, pt
     174            return True
     175        if algorithm == 'local':
     176            if point:
     177                raise ValueError, "Algorithm 'local' cannot be combined with " \
     178                                  "point = True in has_rational_point"
     179            obs = self.local_obstructions(infinite = True, finite = False,
     180                                          read_cache = read_cache)
     181            if obs != []:
     182                if obstruction:
     183                    return False, obs[0]
     184                return False
     185            obs = self.local_obstructions(read_cache = read_cache)
     186            if obs == []:
     187                if obstruction:
     188                    return True, None
     189                return True
     190            if obstruction:
     191                return False, obs[0]
     192            return False
     193        raise ValueError, "Unknown algorithm `%s' in has_rational_point" % algorithm
     194
     195                                           
     196    def is_locally_solvable(self, p):
     197        r"""
     198        Returns True if and only if ``self`` has a solution over the
     199        `p`-adic numbers. Here `p` is a prime number or equals
     200        `-1`, infinity, or `\RR` to denote the infinite place.
     201
     202        EXAMPLES::
     203       
     204            sage: C = Conic(QQ, [1,2,3])
     205            sage: C.is_locally_solvable(-1)
     206            False
     207            sage: C.is_locally_solvable(2)
     208            False
     209            sage: C.is_locally_solvable(3)
     210            True
     211            sage: C.is_locally_solvable(QQ.hom(RR))
     212            False
     213            sage: D = Conic(QQ, [1, 2, -3])
     214            sage: D.is_locally_solvable(infinity)
     215            True
     216            sage: D.is_locally_solvable(RR)
     217            True           
     218
     219        """
     220        D, T = self.diagonal_matrix()
     221        abc = [D[j, j] for j in range(3)]
     222        if abc[2] == 0:
     223            return True
     224        a = -abc[0]/abc[2]
     225        b = -abc[1]/abc[2]
     226        if is_RealField(p) or is_InfinityElement(p):
     227            p = -1
     228        elif is_RingHomomorphism(p):
     229            if p.domain() is QQ and is_RealField(p.codomain()):
     230                p = -1
     231            else:
     232                raise TypeError, "p (=%s) needs to be a prime of base field " \
     233                                 "B ( =`QQ`) in is_locally_solvable" % p
     234        if hilbert_symbol(a, b, p) == -1:
     235            if self._local_obstruction == None:
     236                self._local_obstruction = p
     237            return False
     238        return True
     239
     240
     241    def local_obstructions(self, finite = True, infinite = True, read_cache = True):
     242        r"""
     243        Returns the sequence of finite primes and/or infinite places
     244        such that self is locally solvable at those primes and places.
     245       
     246        The infinite place is denoted `-1`.
     247
     248        The parameters ``finite`` and ``infinite`` (both True by default) are
     249        used to specify whether to look at finite and/or infinite places.
     250        Note that ``finite = True`` involves factorization of the determinant
     251        of ``self``, hence may be slow.
     252       
     253        Local obstructions are cached. The parameter ``read_cache`` specifies
     254        whether to look at the cache before computing anything.
     255
     256        EXAMPLES ::
     257
     258            sage: Conic(QQ, [1, 1, 1]).local_obstructions()
     259            [2, -1]
     260            sage: Conic(QQ, [1, 2, -3]).local_obstructions()
     261            []
     262            sage: Conic(QQ, [1, 2, 3, 4, 5, 6]).local_obstructions()
     263            [41, -1]
     264           
     265        """
     266        obs0 = []
     267        obs1 = []
     268        if infinite:
     269            if read_cache and self._infinite_obstructions != None:
     270                obs0 = self._infinite_obstructions
     271            else:
     272                if not self.is_locally_solvable(-1):
     273                    obs0 = [-1]
     274                self._infinite_obstructions = obs0
     275        if finite:
     276            if read_cache and self._finite_obstructions != None:
     277                obs1 = self._finite_obstructions
     278            else:
     279                candidates = []
     280                if self.determinant() != 0:
     281                    for a in self.symmetric_matrix().list():
     282                        if a != 0:
     283                            for f in a.factor():
     284                                if f[1] < 0 and not f[0] in candidates:
     285                                    candidates.append(f[0])
     286                    for f in (2*self.determinant()).factor():
     287                        if f[1] > 0 and not f[0] in candidates:
     288                            candidates.append(f[0])
     289                for b in candidates:
     290                    if not self.is_locally_solvable(b):
     291                       obs1.append(b)
     292                self._infinite_obstructions = obs1
     293        obs = obs1 + obs0
     294        if finite and infinite:
     295            assert len(obs) % 2 == 0
     296        return obs
     297
     298
     299    def parametrization(self, point=None, morphism=True):
     300        r"""
     301        Return a parametrization `f` of ``self`` together with the
     302        inverse of `f`.
     303
     304        If ``point`` is specified, then that point is used
     305        for the parametrization. Otherwise, use ``self.rational_point()``
     306        to find a point.
     307           
     308        If ``morphism`` is True, then `f` is returned in the form
     309        of a Scheme morphism. Otherwise, it is a tuple of polynomials
     310        that gives the parametrization.
     311       
     312        ALGORITHM:
     313       
     314        Uses Denis Simon's pari script Qfparam.
     315        See ``sage.quadratic_forms.qfsolve.qfparam``.
     316       
     317        EXAMPLES ::
     318
     319            sage: c = Conic([1,1,-1])
     320            sage: c.parametrization()
     321            (Scheme morphism:
     322              From: Projective Space of dimension 1 over Rational Field
     323              To:   Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
     324              Defn: Defined on coordinates by sending (x : y) to
     325                    (2*x*y : x^2 - y^2 : x^2 + y^2),
     326             Scheme morphism:
     327               From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
     328               To:   Projective Space of dimension 1 over Rational Field
     329               Defn: Defined on coordinates by sending (x : y : z) to
     330                     (1/2*x : -1/2*y + 1/2*z))
     331       
     332        An example with ``morphism = False`` ::
     333
     334            sage: R.<x,y,z> = QQ[]
     335            sage: C = Curve(7*x^2 + 2*y*z + z^2)
     336            sage: (p, i) = C.parametrization(morphism = False); (p, i)
     337            ([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])
     338            sage: C.defining_polynomial()(p)
     339            0
     340            sage: i[0](p) / i[1](p)
     341            x/y
     342           
     343        A ``ValueError`` is raised if ``self`` has no rational point ::
     344
     345            sage: C = Conic(x^2 + 2*y^2 + z^2)
     346            sage: C.parametrization()
     347            Traceback (most recent call last):
     348            ...
     349            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!
     350
     351        A ``ValueError`` is raised if ``self`` is not smooth ::
     352       
     353            sage: C = Conic(x^2 + y^2)
     354            sage: C.parametrization()
     355            Traceback (most recent call last):
     356            ...
     357            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.
     358        """
     359        if (not self._parametrization is None) and not point:
     360            par = self._parametrization
     361        else:
     362            if not self.is_smooth():
     363                raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self
     364            if point == None:
     365                point = self.rational_point()
     366            point = Sequence(point)
     367            Q = PolynomialRing(QQ, 'x,y')
     368            [x, y] = Q.gens()
     369            gens = self.ambient_space().gens()
     370            M = self.symmetric_matrix()
     371            M *= lcm([ t.denominator() for t in M.list() ])
     372            par1 = qfparam(M, point)
     373            B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])
     374            # self is in the image of B and does not lie on a line,
     375            # hence B is invertible
     376            A = B.inverse()
     377            par2 = [sum([A[i,j]*gens[j] for j in range(3)]) for i in [1,0]]
     378            par = ([Q(pol(x/y)*y**2) for pol in par1], par2)
     379            if self._parametrization is None:
     380                self._parametrization = par
     381        if not morphism:
     382            return par
     383        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
     384        return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
     385
  • new file sage/schemes/plane_conics/constructor.py

    diff -r c58f82863c75 -r 9f7d2c8e89e9 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 c58f82863c75 -r 9f7d2c8e89e9 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 c58f82863c75 -r 9f7d2c8e89e9 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',