Ticket #727: trac_727_conic_combined_1-6.patch

File trac_727_conic_combined_1-6.patch, 103.6 KB (added by Marco Streng, 12 years ago)

apply only this latest file

  • doc/en/reference/index.rst

    # HG changeset patch
    # User Marco Streng <marco.streng@gmail.com>
    # Date 1279489664 -7200
    # Node ID 1a3f494ca6f0855d689e54ad020047a43a9d3a27
    # Parent  8dec8b43ccca5f104b1e280cb33c8f4c2c1b8f85
    * * *
    Trac 727: Conic class using Simon's code for finding points over QQ and using
    Pari to find points over number fields. Bad version of Hilbert symbols over
    number fields.
    * * *
    Trac 727 the missing file __init__.py
    * * *
    Trac 727: replace unfinished hilbert symbols by 9334
    * * *
    Trac 727: split conic class into many classes
    * * *
    Trac 727: corrections and more tests for Conics
    * * *
    Trac 727: fix doctests, remove global field
    
    diff -r 8dec8b43ccca -r 1a3f494ca6f0 doc/en/reference/index.rst
    a b  
    8888   modfrm
    8989   modabvar
    9090   modmisc
     91   quadratic_forms
    9192
    9293   history_and_license
    9394
  • doc/en/reference/plane_curves.rst

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 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 doc/en/reference/quadratic_forms.rst

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 doc/en/reference/quadratic_forms.rst
    - +  
     1.. _ch:schemes:
     2
     3Quadratic Forms
     4===============
     5
     6.. toctree::
     7   :maxdepth: 2
     8
     9    sage/quadratic_forms/fsolve.py
     10
  • new file sage/quadratic_forms/qfsolve.py

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 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
     6AUTHOR:
     7    Denis Simon (GP code)
     8    Nick Alexander (Sage interface)
     9"""
     10
     11#*****************************************************************************
     12#       Copyright (C) 2008 William Stein <wstein@gmail.com>
     13#
     14#  Distributed under the terms of the GNU General Public License (GPL)
     15#
     16#    This code is distributed in the hope that it will be useful,
     17#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     18#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     19#    General Public License for more details.
     20#
     21#  The full text of the GPL is available at:
     22#
     23#                  http://www.gnu.org/licenses/
     24#*****************************************************************************
     25
     26from sage.interfaces.gp import Gp
     27from sage.rings.all import ZZ, QQ
     28from sage.libs.pari.gen import pari
     29
     30_gp_for_simon_interpreter = None    # Global GP interpreter for Denis Simon's code
     31def _gp_for_simon():
     32    r"""
     33    Start a GP interpreter for the use of Denis Simon's Qfsolve and Qfparam
     34    if it is not started already.
     35   
     36    EXAMPLE ::
     37   
     38        sage: from sage.quadratic_forms.qfsolve import _gp_for_simon
     39        sage: _gp_for_simon()
     40        GP/PARI interpreter
     41    """
     42    global _gp_for_simon_interpreter
     43    if _gp_for_simon_interpreter is None:
     44        _gp_for_simon_interpreter = Gp(script_subdirectory='simon')
     45        _gp_for_simon_interpreter.read("qfsolve.gp")
     46    return _gp_for_simon_interpreter
     47
     48# \\ - Qfsolve(G,factD): pour resoudre l'equation quadratique X^t*G*X = 0
     49# \\ G doit etre une matrice symetrique n*n, a coefficients dans Z.
     50# \\ S'il n'existe pas de solution, la reponse est un entier
     51# \\ indiquant un corps local dans lequel aucune solution n'existe
     52# \\ (-1 pour les reels, p pour Q_p).
     53# \\ Si on connait la factorisation de -abs(2*matdet(G)),
     54# \\ on peut la passer par le parametre factD pour gagner du temps.
     55# \\
     56# \\ - Qfparam(G,sol,fl): pour parametrer les solutions de la forme
     57# \\ quadratique ternaire G, en utilisant la solution particuliere sol.
     58# \\ si fl>0, la 'fl'eme forme quadratique est reduite.
     59
     60def Qfsolve(G, factD=None):
     61    r"""Find a solution to (x,y,z)^t*G*(x,y,z) = 0.
     62
     63    If successful, returns a triple of rational numbers (x0, y0, z0).
     64    If unsuccessful, returns -1 if no solutions exists over the reals and a
     65    prime p if no solution exists over the p-adic field Q_p.
     66
     67    EXAMPLES:
     68        sage: from sage.quadratic_forms.qfsolve import Qfsolve
     69        sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M
     70        [  0   0 -12]
     71        [  0 -12   0]
     72        [-12   0  -1]
     73        sage: sol = Qfsolve(M); sol
     74        (1, 0, 0)
     75        sage: sol[0].parent() is QQ
     76        True
     77       
     78        sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
     79        sage: ret = Qfsolve(M); ret
     80        -1
     81        sage: ret.parent() is ZZ
     82        True
     83
     84        sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, -7]])
     85        sage: Qfsolve(M)
     86        7
     87    """
     88    gp = _gp_for_simon()
     89    if factD is not None:
     90        raise NotImplementedError
     91    ret = pari(gp('Qfsolve(%s)' % G._pari_()))
     92    if ret.type() == 't_COL':
     93        return (QQ(ret[0]), QQ(ret[1]), QQ(ret[2]))
     94    return ZZ(ret)
     95
     96def Qfparam(G, sol):
     97    r"""
     98
     99    EXAMPLES:
     100        sage: from sage.quadratic_forms.qfsolve import Qfsolve, Qfparam
     101        sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M
     102        [  0   0 -12]
     103        [  0 -12   0]
     104        [-12   0  -1]
     105        sage: sol = Qfsolve(M);
     106        sage: ret = Qfparam(M, sol); ret
     107        (-t^2 - 12, 24*t, 24*t^2)
     108        sage: ret[0].parent() is QQ['t']
     109        True
     110    """
     111    gp = _gp_for_simon()
     112    R = QQ['t']
     113    str = 'Qfparam(%s, (%s)~)*[t^2,t,1]~' % (G._pari_(), pari(gp(sol))._pari_())
     114    ret = pari(gp(str))
     115    return (R(ret[0]), R(ret[1]), R(ret[2]))
     116
     117qfsolve = Qfsolve
     118qfparam = Qfparam
  • sage/schemes/all.py

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 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 8dec8b43ccca -r 1a3f494ca6f0 sage/schemes/plane_conics/__init__.py
    - +  
     1
     2
  • new file sage/schemes/plane_conics/all.py

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 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 8dec8b43ccca -r 1a3f494ca6f0 sage/schemes/plane_conics/con_field.py
    - +  
     1r"""
     2Projective plane conics over a field.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-08-07)
     7
     8- Nick Alexander (2008-01-08)
     9
     10"""
     11#*****************************************************************************
     12#       Copyright (C) 2008 Nick Alexander <ncalexander@gmail.com>
     13#       Copyright (C) 2009/2010 Marco Streng <marco.streng@gmail.com>
     14#
     15#  Distributed under the terms of the GNU General Public License (GPL)
     16#
     17#    This code is distributed in the hope that it will be useful,
     18#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     19#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     20#    General Public License for more details.
     21#
     22#  The full text of the GPL is available at:
     23#
     24#                  http://www.gnu.org/licenses/
     25#*****************************************************************************
     26
     27from sage.rings.all import (PolynomialRing, QQ,
     28                            is_ComplexField, is_RealField,
     29                            is_Field)
     30from sage.modules.free_module_element import vector
     31from sage.structure.sequence import Sequence
     32from sage.structure.element import is_Vector
     33from sage.schemes.generic.projective_space import ProjectiveSpace
     34from sage.matrix.constructor import Matrix
     35from sage.matrix.matrix import is_Matrix
     36
     37from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic
     38
     39class ProjectiveConic_field(ProjectiveCurve_generic):
     40    r"""
     41    Create a projective plane conic curve over a field.
     42    See ``Conic`` for full documentation.
     43   
     44    EXAMPLES::
     45   
     46        sage: K = FractionField(PolynomialRing(QQ, 't'))
     47        sage: P.<X, Y, Z> = K[]
     48        sage: Conic(X^2 + Y^2 - Z^2)
     49        Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by X^2 + Y^2 - Z^2
     50       
     51    TESTS::
     52   
     53        sage: K = FractionField(PolynomialRing(QQ, 't'))
     54        sage: Conic([K(1), 1, -1])._test_pickling()
     55    """
     56    def __init__(self, A, f):
     57        r"""
     58        See ``Conic`` for full documentation.
     59
     60        EXAMPLES:
     61
     62        ::
     63
     64            sage: c = Conic([1, 1, 1]); c
     65            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     66        """
     67        ProjectiveCurve_generic.__init__(self, A, f)
     68        self._coefficients = [f[(2,0,0)], f[(1,1,0)], f[(1,0,1)],
     69                                f[(0,2,0)], f[(0,1,1)], f[(0,0,2)]]
     70        self._parametrization = None
     71        self._diagonal_matrix = None
     72       
     73        self._rational_point = None
     74
     75
     76
     77
     78    def _repr_type(self):
     79        r"""
     80        Returns ``'Projective Conic'``, which is the first part of the
     81        plain text representation of this object as output by
     82        the function ``_repr_`` of the class ``Curve_generic``.
     83
     84        EXAMPLES::
     85
     86            sage: c = Conic([1, 1, 1]); c
     87            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     88            sage: c._repr_()
     89            'Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2'
     90            sage: c._repr_type()
     91            'Projective Conic'
     92        """
     93        return "Projective Conic"
     94
     95    def base_extend(self, S):
     96        r"""
     97        Returns the conic over ``S`` given by the same equation as ``self``.
     98
     99        EXAMPLES::
     100
     101            sage: c = Conic([1, 1, 1]); c
     102            Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2
     103            sage: c.has_rational_point()
     104            False
     105            sage: d = c.base_extend(QuadraticField(-1, 'i')); d
     106            Projective Conic Curve over Number Field in i with defining polynomial x^2 + 1 defined by x^2 + y^2 + z^2
     107            sage: d.rational_point(algorithm = 'rnfisnorm')
     108            (i : 1 : 0)
     109        """
     110        if is_Field(S):
     111            B = self.base_ring()
     112            if B == S:
     113                return self
     114            if not S.has_coerce_map_from(B):
     115                raise ValueError, "No natural map from the base ring of self " \
     116                                  "(= %s) to S (= %s)" % (self, S)
     117            from constructor import Conic
     118            con = Conic([S(c) for c in self.coefficients()], \
     119                        self.variable_names())
     120            if self._rational_point != None:
     121                pt = [S(c) for c in Sequence(self._rational_point)]
     122                if not pt == [0,0,0]:
     123                    # The following line stores the point in the cache
     124                    # if (and only if) there is no point in the cache.
     125                    pt = con.point(pt)
     126            return con
     127        return ProjectiveCurve_generic.base_extend(self, S)
     128   
     129    def cache_point(self, p):
     130        r"""
     131        Replace the point in the cache of ``self`` by ``p`` for use
     132        by ``self.rational_point()`` and ``self.parametrization()``.
     133       
     134        EXAMPLES::
     135
     136            sage: c = Conic([1, -1, 1])
     137            sage: c.point([15, 17, 8])
     138            (15/8 : 17/8 : 1)
     139            sage: c.rational_point()
     140            (15/8 : 17/8 : 1)
     141            sage: c.cache_point(c.rational_point(read_cache = False))
     142            sage: c.rational_point()
     143            (1 : 1 : 0)
     144        """
     145        if isinstance(p, (tuple, list)):
     146            p = self.point(p)
     147        self._rational_point = p
     148
     149    def coefficients(self):
     150        r"""
     151        Gives a the `6` coefficients of the conic ``self``
     152        in lexicographic order.
     153       
     154        EXAMPLES::
     155       
     156            sage: Conic(QQ, [1,2,3,4,5,6]).coefficients()
     157            [1, 2, 3, 4, 5, 6]
     158
     159            sage: P.<x,y,z> = GF(13)[]
     160            sage: a = Conic(x^2+5*x*y+y^2+z^2).coefficients(); a
     161            [1, 5, 0, 1, 0, 1]
     162            sage: Conic(a)
     163            Projective Conic Curve over Finite Field of size 13 defined by x^2 + 5*x*y + y^2 + z^2
     164        """
     165        return self._coefficients
     166       
     167       
     168    def derivative_matrix(self):
     169        r"""
     170        Gives the derivative of the defining polynomial of
     171        the conic ``self``, which is a linear map,
     172        as a `3 \times 3` matrix.
     173       
     174        EXAMPLES:
     175       
     176        In characteristic different from `2`, the
     177        derivative matrix is twice the symmetric matrix:
     178
     179        ::
     180       
     181            sage: c = Conic(QQ, [1,1,1,1,1,0])
     182            sage: c.symmetric_matrix()
     183            [  1 1/2 1/2]
     184            [1/2   1 1/2]
     185            [1/2 1/2   0]
     186            sage: c.derivative_matrix()
     187            [2 1 1]
     188            [1 2 1]
     189            [1 1 0]
     190
     191        An example in characteristic `2`:
     192
     193        ::
     194
     195            sage: P.<t> = GF(2)[]
     196            sage: c = Conic([t, 1, t^2, 1, 1, 0]); c
     197            Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using NTL) defined by t*x^2 + x*y + y^2 + t^2*x*z + y*z
     198            sage: c.is_smooth()
     199            True
     200            sage: c.derivative_matrix()
     201            [  0   1 t^2]
     202            [  1   0   1]
     203            [t^2   1   0]
     204        """
     205        from sage.matrix.constructor import matrix
     206        [a,b,c,d,e,f] = self.coefficients()
     207        return matrix([[ 2*a ,   b ,   c ],
     208                       [   b , 2*d ,   e ],
     209                       [   c ,   e , 2*f ]])
     210       
     211    def determinant(self):
     212        r"""
     213        Returns the determinant of the symmetric matrix that defines
     214        the conic ``self``.
     215       
     216        This is defined only if the base field has characteristic
     217        different from `2`.
     218
     219        EXAMPLES:
     220
     221        ::
     222
     223            sage: C = Conic([1,2,3,4,5,6])
     224            sage: C.determinant()
     225            41/4
     226            sage: C.symmetric_matrix().determinant()
     227            41/4
     228
     229        Determinants are only defined in characteristic different from `2`::
     230
     231            sage: C = Conic(GF(2), [1, 1, 1, 1, 1, 0])
     232            sage: C.is_smooth()
     233            True
     234            sage: C.determinant()
     235            Traceback (most recent call last):
     236            ...
     237            ValueError: The conic self (= Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z) has no symmetric matrix because the base field has characteristic 2
     238        """
     239        return self.symmetric_matrix().determinant()
     240
     241    det = 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.det() == 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(algorithm = 'rnfisnorm')
     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 number fields ::
     829           
     830            sage: P.<x> = QQ[]
     831            sage: L.<b> = NumberField(x^3-5)
     832            sage: C = Conic(L, [3, 2, -5])
     833            sage: C.rational_point(algorithm = 'rnfisnorm')  # long time (1/2 second), output is random
     834            (37632*b^2 + 88168*b - 260801 : -99528*b^2 + 153348*b + 28799 : 1)
     835       
     836        Examples over finite fields ::
     837       
     838            sage: F.<a> = FiniteField(7^20)
     839            sage: C = Conic([1, a, -5]); C
     840            Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + (a)*y^2 + 2*z^2
     841            sage: C.rational_point()  # output is random
     842            (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)
     843             
     844        Examples over `\RR` and `\CC` ::
     845
     846            sage: Conic(CC, [1, 2, 3]).rational_point()
     847            (0 : 1.22474487139159*I : 1)
     848
     849            sage: Conic(RR, [1, 1, 1]).rational_point()
     850            Traceback (most recent call last):
     851            ...
     852            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!
     853        """
     854        bl,pt = self.has_rational_point(point = True, algorithm = algorithm,
     855                                        read_cache = read_cache)
     856        if bl:
     857            return pt
     858        raise ValueError, "Conic %s has no rational points over %s!" % \
     859                          (self, self.ambient_space().base_ring())
     860
     861
     862    def singular_point(self):
     863        r"""
     864        Returns a singular rational point of ``self``
     865       
     866        EXAMPLES:
     867       
     868        ::
     869
     870            sage: Conic(GF(2), [1,1,1,1,1,1]).singular_point()
     871            (1 : 1 : 1)
     872
     873        ``ValueError`` is raised if the conic has no rational singular point
     874           
     875        ::
     876
     877            sage: Conic(QQ, [1,1,1,1,1,1]).singular_point()
     878            Traceback (most recent call last):
     879            ...
     880            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
     881        """
     882        b = self.has_singular_point(point = True)
     883        if not b[0]:
     884            raise ValueError, "The conic self (= %s) has no rational " \
     885                              "singular point" % self
     886        return b[1]
     887
     888    def symmetric_matrix(self):
     889        r"""
     890        The symmetric matrix `M` such that `(x y z) M (x y z)^t`
     891        is the defining equation of ``self``.
     892       
     893        EXAMPLES ::
     894       
     895            sage: R.<x, y, z> = QQ[]
     896            sage: C = Conic(x^2 + x*y/2 + y^2 + z^2)
     897            sage: C.symmetric_matrix()
     898            [  1 1/4   0]
     899            [1/4   1   0]
     900            [  0   0   1]
     901
     902            sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
     903            sage: v = vector([x, y, z])
     904            sage: v * C.symmetric_matrix() * v
     905            x^2 + 2*x*y + y^2 + 3*x*z + z^2
     906        """
     907        [a,b,c,d,e,f] = self.coefficients()
     908        if self.base_ring().characteristic() == 2:
     909            if b == 0 and c == 0 and e == 0:
     910                return matrix([[a,0,0],[0,d,0],[0,0,f]])
     911            raise ValueError, "The conic self (= %s) has no symmetric matrix " \
     912                              "because the base field has characteristic 2" % \
     913                              self
     914        from sage.matrix.constructor import matrix
     915        return matrix([[  a , b/2, c/2 ],
     916                       [ b/2,  d , e/2 ],
     917                       [ c/2, e/2,  f  ]])
     918
     919
     920    def upper_triangular_matrix(self):
     921        r"""
     922        The upper-triangular matrix `M` such that `(x y z) M (x y z)^t`
     923        is the defining equation of ``self``.
     924
     925        EXAMPLES::
     926
     927            sage: R.<x, y, z> = QQ[]
     928            sage: C = Conic(x^2 + x*y + y^2 + z^2)
     929            sage: C.upper_triangular_matrix()
     930            [1 1 0]
     931            [0 1 0]
     932            [0 0 1]
     933
     934            sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
     935            sage: v = vector([x, y, z])
     936            sage: v * C.upper_triangular_matrix() * v
     937            x^2 + 2*x*y + y^2 + 3*x*z + z^2
     938        """
     939        from sage.matrix.constructor import matrix
     940        [a,b,c,d,e,f] = self.coefficients()
     941        return matrix([[ a, b, c ],
     942                       [ 0, d, e ],
     943                       [ 0, 0, f ]])
     944   
     945    def variable_names(self):
     946        r"""
     947        Returns the variable names of the defining polynomial
     948        of ``self``.
     949
     950        EXAMPLES:
     951
     952        ::
     953
     954            sage: c=Conic([1,1,0,1,0,1], 'x,y,z')
     955            sage: c.variable_names()
     956            ('x', 'y', 'z')
     957            sage: c.variable_name()
     958            'x'
     959           
     960        The function ``variable_names()`` is required
     961        for the following construction:
     962       
     963        ::
     964       
     965            sage: C.<p,q,r> = Conic(QQ, [1, 1, 1])
     966            sage: C
     967            Projective Conic Curve over Rational Field defined by p^2 + q^2 + r^2
     968
     969        """
     970        return self.defining_polynomial().parent().variable_names()
     971   
     972       
     973       
     974
     975 
  • new file sage/schemes/plane_conics/con_finite_field.py

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

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

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

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 sage/schemes/plane_conics/constructor.py
    - +  
     1r"""
     2Plane conic constructor.
     3
     4AUTHORS:
     5
     6- Marco Streng (2010-08-07)
     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
  • new file sage/schemes/plane_conics/rnfisnorm.py

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 sage/schemes/plane_conics/rnfisnorm.py
    - +  
     1r"""
     2Solve relative quadratic norm equations using PARI.
     3
     4The function rnfisnorm is a wrapper for the PARI function with the same name.
     5On input a relative quadratic number field `L` and an element `x` of its
     6base field `K`, the function ``rnfisnorm(L, x)`` determines whether `x` is the
     7relative norm `N_{L/K}(y)` of an element `y\in L`.
     8
     9AUTHORS:
     10
     11- Marco Streng (2009-08-07)
     12
     13"""
     14#*****************************************************************************
     15#       Copyright (C) 2009 Marco Streng <marco.streng@gmail.com>
     16#
     17#  Distributed under the terms of the GNU General Public License (GPL)
     18#
     19#    This code is distributed in the hope that it will be useful,
     20#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     21#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22#    General Public License for more details.
     23#
     24#  The full text of the GPL is available at:
     25#
     26#                  http://www.gnu.org/licenses/
     27#*****************************************************************************
     28
     29from sage.libs.pari.gen import pari
     30from sage.rings.all import (NumberField, PolynomialRing, is_NumberField,
     31                            is_NumberFieldElement, is_AbsoluteNumberField,
     32                            is_RationalField, ZZ, QQ)
     33from sage.rings.arith import LCM                           
     34from sage.structure.sequence import Sequence
     35
     36
     37
     38def _rnfisnorm(L, x, galois_check = 2, extra_primes = 0):
     39    r"""
     40    WARNING:
     41   
     42        This function will be removed after Trac #2329 is completed.
     43        Then use ``x.is_norm(L)`` instead.
     44   
     45    For a relative number field `L` and an element `x` of its base field `K`,
     46    determine whether `x` is the relative norm `N_{L/K}(y)` of an element
     47    `y\in L`.
     48   
     49    The output takes the form ``(True, y)`` if the answer is positive, and
     50    ``(False, None)`` otherwise.
     51   
     52    The output is guaranteed if `L/K` is Galois. Otherwise, the parameters
     53    ``galois_check`` and ``extra_primes`` can be used as follows.
     54   
     55    ``galois_check`` can be 0, 1, or 2.
     56   
     57        0. do not care if L/K is Galois
     58        1. assume L/K is Galois
     59        2. let PARI determine whether L/K is Galois
     60   
     61    ``extra_primes``:
     62        The norm equation is solved in `S`-units, where `S` is a set determined
     63        by the PARI. If extra_primes is a positive integer, add all primes
     64        ``<=`` extra_primes to `S`. If extra_primes is a negative integer, add
     65        all primes dividing extra_primes to `S`. If `S` contains all primes
     66        less than `12`log(disc(`M`)), where `M` is the normal closure of `L/K`,
     67        then the output is guaranteed under GRH.
     68   
     69    ALGORITHM:
     70   
     71        Uses PARI's rnfisnorm or bnfisnorm to find a solution in the `S`-unit
     72        group for a suitable set of primes `S` of `L`.
     73   
     74    EXAMPLES:
     75    This also works over `\QQ`.
     76   
     77    ::
     78   
     79        sage: from sage.schemes.plane_conics.rnfisnorm import _rnfisnorm
     80        sage: _rnfisnorm(5/4, 1/5)
     81        (True, (-1/2, -1/5))
     82
     83    Absolute number fields are interpreted as relative fields over `\QQ`.
     84   
     85    ::
     86        sage: from sage.schemes.plane_conics.rnfisnorm import _rnfisnorm
     87        sage: _rnfisnorm(QuadraticField(-1, 'i'), 2)
     88        (True, i + 1)
     89        sage: _rnfisnorm(CyclotomicField(7), 7)
     90        (True,  zeta7 - 1)
     91        sage: _rnfisnorm(CyclotomicField(7), 3)
     92        (False, None)
     93
     94    A higher degree example:
     95   
     96    ::
     97   
     98        sage: from sage.schemes.plane_conics.rnfisnorm import _rnfisnorm
     99        sage: P.<x> = QQ[]
     100        sage: K.<a> = NumberField(x^3 + x + 1)
     101        sage: Q.<X> = K[]
     102        sage: L.<b> = NumberField(X^4 + a)
     103        sage: t = _rnfisnorm(L, -a); t
     104        (True, b^3 + 1)
     105        sage: t[1].norm(K) == -a
     106        True
     107        sage: _rnfisnorm(K, 2)
     108        (False, None)
     109        sage: t = _rnfisnorm(L, 2); t
     110        (True, -a*b^3 + b^2 + (a^2 + 1)*b + a^2 + 1)
     111        sage: t[1].norm(K) == 2
     112        True
     113
     114    A relative quadratic number field `L` over `K` can be given by an
     115    element `z` of `K` such that `L = K(\sqrt{z})`. In that case, the
     116    output `y \in L` is given by the tuple `(a, b)` such that
     117    `y = a + b\sqrt{z}`.
     118   
     119    ::
     120   
     121        sage: from sage.schemes.plane_conics.rnfisnorm import _rnfisnorm
     122        sage: _rnfisnorm(-1, 2)
     123        (True, (1, 1))
     124        sage: K.<b> = NumberField(x^5+x+3)
     125        sage: _rnfisnorm(b, 1 - b)
     126        (True, (-1, 1))
     127        sage: _rnfisnorm(b/2, -5)
     128        (False, None)
     129        sage: _rnfisnorm(b, (1 - b)/3)
     130        (False, None)
     131    """
     132    if is_NumberFieldElement(L) or L in QQ:
     133        s = Sequence([L, x])
     134        K = s.universe()
     135        if K == ZZ:
     136            K = QQ
     137        elif not (K == QQ or is_AbsoluteNumberField(K)):
     138            raise ValueError, "L (=%s) and x (=%s) must lie in the same " \
     139                              "number field" % (L, x)
     140        X = PolynomialRing(K, 'X').gen()
     141        x = K(x)
     142        den = L.denominator()
     143        L = NumberField(X**2-L*den**2, K.variable_name() + 'L')
     144        ret = _rnfisnorm(L, x, galois_check = galois_check,
     145                      extra_primes = extra_primes)
     146        if ret[0]:
     147            ret1 = ret[1].vector()
     148            return (True, (ret1[0], ret1[1]*den))
     149        return ret
     150    elif is_NumberField(L):
     151        K = L.base_field()
     152        x = K(x)
     153    else:
     154        raise TypeError, "L (=%s) must be a number field or an element of a " \
     155                         "number field" % L   
     156    if is_RationalField(K) or (is_AbsoluteNumberField(K) and K.degree() == 1):
     157        pol1 = 'y'
     158        pol2 = L.pari_polynomial()
     159        xpari = QQ(x)._pari_()
     160    elif is_AbsoluteNumberField(K):
     161        pol1 = K.pari_polynomial('y')
     162        pol2 = L.pari_relative_polynomial().lift()
     163        xpari = x._pari_('y')
     164    else:
     165        raise ValueError, "Base field of L (=%s) needs to be an absolute" \
     166                          "number field in _rnfisnorm" % L
     167    T = pari("rnfisnorm(rnfisnorminit(%s, %s, %s), %s, %s)" % (pol1, \
     168                             pol2, galois_check, xpari, extra_primes))
     169    if T[1] == 1:
     170        Q = PolynomialRing(K, 'X')
     171        u = T[0].lift()
     172        d = ZZ(LCM([u.polcoeff(k).eval(0).denominator() for k in range(u.lift().poldegree()+1)]))
     173        return True, L(Q(d*u))/d
     174    return False, None
     175   
     176   
     177   
  • sage/schemes/plane_curves/constructor.py

    diff -r 8dec8b43ccca -r 1a3f494ca6f0 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 8dec8b43ccca -r 1a3f494ca6f0 setup.py
    a b  
    907907                     'sage.schemes.generic',
    908908                     'sage.schemes.jacobians',
    909909                     'sage.schemes.plane_curves',
     910                     'sage.schemes.plane_conics',
    910911                     'sage.schemes.plane_quartics',
    911912                     'sage.schemes.elliptic_curves',
    912913                     'sage.schemes.hyperelliptic_curves',