def __init__(self, A, f): r""" See ``Conic`` for full documentation. EXAMPLES:: sage: Conic([1, 1, 1]) Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 """ ProjectiveConic_number_field.__init__(self, A, f)
def has_rational_point(self, point = False, obstruction = False, algorithm = 'default', read_cache = True): r""" Returns True if and only if ``self`` has a point defined over `\QQ`. If ``point`` and ``obstruction`` are both False (default), then the output is a boolean ``out`` saying whether ``self`` has a rational point. If ``point`` or ``obstruction`` is True, then the output is a pair ``(out, S)``, where ``out`` is as above and the following holds: - if ``point`` is True and ``self`` has a rational point, then ``S`` is a rational point, - if ``obstruction`` is True and ``self`` has no rational point, then ``S`` is a prime such that no rational point exists over the completion at ``S`` or `-1` if no point exists over `\RR`. Points and obstructions are cached, whenever they are found. Cached information is used if and only if ``read_cache`` is True. ALGORITHM: The parameter ``algorithm`` specifies the algorithm to be used: - ``'qfsolve'`` -- Use PARI/GP function ``qfsolve`` - ``'rnfisnorm'`` -- Use PARI's function rnfisnorm (cannot be combined with ``obstruction = True``) - ``'local'`` -- Check if a local solution exists for all primes and infinite places of `\QQ` and apply the Hasse principle (cannot be combined with ``point = True``) - ``'default'`` -- Use ``'qfsolve'`` - ``'magma'`` (requires Magma to be installed) -- delegates the task to the Magma computer algebra system. EXAMPLES:: sage: C = Conic(QQ, [1, 2, -3]) sage: C.has_rational_point(point = True) (True, (1 : 1 : 1)) sage: D = Conic(QQ, [1, 3, -5]) sage: D.has_rational_point(point = True) (False, 3) sage: P.<X,Y,Z> = QQ[] sage: E = Curve(X^2 + Y^2 + Z^2); E Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2 sage: E.has_rational_point(obstruction = True) (False, -1) The following would not terminate quickly with ``algorithm = 'rnfisnorm'`` :: sage: C = Conic(QQ, [1, 113922743, -310146482690273725409]) sage: C.has_rational_point(point = True) (True, (-76842858034579/5424 : -5316144401/5424 : 1)) sage: C.has_rational_point(algorithm = 'local', read_cache = False) True sage: C.has_rational_point(point=True, algorithm='magma', read_cache=False) # optional - magma (True, (30106379962113/7913 : 12747947692/7913 : 1)) TESTS: Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors and returns consistent answers for all algorithms. Check if all points returned are valid. :: sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)])) sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)] sage: d = [] 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 sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d]) 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]]) """ if read_cache: if self._rational_point is not None: if point or obstruction: return True, self._rational_point else: return True if self._local_obstruction is not None: if point or obstruction: return False, self._local_obstruction else: return False if (not point) and self._finite_obstructions == [] and \ self._infinite_obstructions == []: if obstruction: return True, None return True if self.has_singular_point(): if point: return self.has_singular_point(point = True) if obstruction: return True, None return True if algorithm == 'default' or algorithm == 'qfsolve': M = self.symmetric_matrix() M *= lcm([ t.denominator() for t in M.list() ]) pt = qfsolve(M) if pt in ZZ: if self._local_obstruction is None: self._local_obstruction = pt if point or obstruction: return False, pt return False pt = self.point([pt[0], pt[1], pt[2]]) if point or obstruction: return True, pt return True ret = ProjectiveConic_number_field.has_rational_point( \ self, point = point, \ obstruction = obstruction, \ algorithm = algorithm, \ read_cache = read_cache) if point or obstruction: if is_RingHomomorphism(ret[1]): ret[1] = -1 return ret
def Conic(base_field, F=None, names=None, unique=True): r""" Return the plane projective conic curve defined by ``F`` over ``base_field``. The input form ``Conic(F, names=None)`` is also accepted, in which case the fraction field of the base ring of ``F`` is used as base field. INPUT: - ``base_field`` -- The base field of the conic. - ``names`` -- a list, tuple, or comma separated string of three variable names specifying the names of the coordinate functions of the ambient space `\Bold{P}^3`. If not specified or read off from ``F``, then this defaults to ``'x,y,z'``. - ``F`` -- a polynomial, list, matrix, ternary quadratic form, or list or tuple of 5 points in the plane. If ``F`` is a polynomial or quadratic form, then the output is the curve in the projective plane defined by ``F = 0``. If ``F`` is a polynomial, then it must be a polynomial of degree at most 2 in 2 variables, or a homogeneous polynomial in of degree 2 in 3 variables. If ``F`` is a matrix, then the output is the zero locus of `(x,y,z) F (x,y,z)^t`. If ``F`` is a list of coefficients, then it has length 3 or 6 and gives the coefficients of the monomials `x^2, y^2, z^2` or all 6 monomials `x^2, xy, xz, y^2, yz, z^2` in lexicographic order. If ``F`` is a list of 5 points in the plane, then the output is a conic through those points. - ``unique`` -- Used only if ``F`` is a list of points in the plane. If the conic through the points is not unique, then raise ``ValueError`` if and only if ``unique`` is True OUTPUT: A plane projective conic curve defined by ``F`` over a field. EXAMPLES: Conic curves given by polynomials :: sage: X,Y,Z = QQ['X,Y,Z'].gens() sage: Conic(X^2 - X*Y + Y^2 - Z^2) Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2 sage: x,y = GF(7)['x,y'].gens() sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W') Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2 Conic curves given by matrices :: sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z') Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2 sage: x,y,z = GF(11)['x,y,z'].gens() sage: C = Conic(x^2+y^2-2*z^2); C Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 sage: Conic(C.symmetric_matrix(), 'x,y,z') Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2 Conics given by coefficients :: sage: Conic(QQ, [1,2,3]) Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2 sage: Conic(GF(7), [1,2,3,4,5,6], 'X') 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 The conic through a set of points :: sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C 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 sage: C.rational_point() (10 : 2 : 1) sage: C.point([3,4]) (3 : 4 : 1) sage: a=AffineSpace(GF(13),2) sage: Conic([a([x,x^2]) for x in range(5)]) Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z """ if not (is_IntegralDomain(base_field) or base_field == None): if names is None: names = F F = base_field base_field = None if isinstance(F, (list,tuple)): if len(F) == 1: return Conic(base_field, F[0], names) if names == None: names = 'x,y,z' if len(F) == 5: L=[] for f in F: if isinstance(f, SchemeMorphism_point_affine): C = Sequence(f, universe = base_field) if len(C) != 2: raise TypeError, "points in F (=%s) must be planar"%F C.append(1) elif isinstance(f, SchemeMorphism_point_projective_field): C = Sequence(f, universe = base_field) elif isinstance(f, (list, tuple)): C = Sequence(f, universe = base_field) if len(C) == 2: C.append(1) else: raise TypeError, "F (=%s) must be a sequence of planar " \ "points" % F if len(C) != 3: raise TypeError, "points in F (=%s) must be planar" % F P = C.universe() if not is_IntegralDomain(P): raise TypeError, "coordinates of points in F (=%s) must " \ "be in an integral domain" % F L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2, C[1]*C[2], C[2]**2], P.fraction_field())) M=Matrix(L) if unique and M.rank() != 5: raise ValueError, "points in F (=%s) do not define a unique " \ "conic" % F con = Conic(base_field, Sequence(M.right_kernel().gen()), names) con.point(F[0]) return con F = Sequence(F, universe = base_field) base_field = F.universe().fraction_field() temp_ring = PolynomialRing(base_field, 3, names) (x,y,z) = temp_ring.gens() if len(F) == 3: return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2) if len(F) == 6: return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \ F[4]*y*z + F[5]*z**2) raise TypeError, "F (=%s) must be a sequence of 3 or 6" \ "coefficients" % F if is_QuadraticForm(F): F = F.matrix() if is_Matrix(F) and F.is_square() and F.ncols() == 3: if names == None: names = 'x,y,z' temp_ring = PolynomialRing(F.base_ring(), 3, names) F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) if not is_MPolynomial(F): raise TypeError, "F (=%s) must be a three-variable polynomial or " \ "a sequence of points or coefficients" % F if F.total_degree() != 2: raise TypeError, "F (=%s) must have degree 2" % F if base_field == None: base_field = F.base_ring() if not is_IntegralDomain(base_field): raise ValueError, "Base field (=%s) must be a field" % base_field base_field = base_field.fraction_field() if names == None: names = F.parent().variable_names() pol_ring = PolynomialRing(base_field, 3, names) if F.parent().ngens() == 2: (x,y,z) = pol_ring.gens() F = pol_ring(F(x/z,y/z)*z**2) if F == 0: raise ValueError, "F must be nonzero over base field %s" % base_field if F.total_degree() != 2: raise TypeError, "F (=%s) must have degree 2 over base field %s" % \ (F, base_field) if F.parent().ngens() == 3: P2 = ProjectiveSpace(2, base_field, names) if is_PrimeFiniteField(base_field): return ProjectiveConic_prime_finite_field(P2, F) if is_FiniteField(base_field): return ProjectiveConic_finite_field(P2, F) if is_RationalField(base_field): return ProjectiveConic_rational_field(P2, F) if is_NumberField(base_field): return ProjectiveConic_number_field(P2, F) return ProjectiveConic_field(P2, F) raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
def has_rational_point(self, point=False, obstruction=False, algorithm='default', read_cache=True): r""" Returns True if and only if ``self`` has a point defined over `\QQ`. If ``point`` and ``obstruction`` are both False (default), then the output is a boolean ``out`` saying whether ``self`` has a rational point. If ``point`` or ``obstruction`` is True, then the output is a pair ``(out, S)``, where ``out`` is as above and the following holds: - if ``point`` is True and ``self`` has a rational point, then ``S`` is a rational point, - if ``obstruction`` is True and ``self`` has no rational point, then ``S`` is a prime such that no rational point exists over the completion at ``S`` or `-1` if no point exists over `\RR`. Points and obstructions are cached, whenever they are found. Cached information is used if and only if ``read_cache`` is True. ALGORITHM: The parameter ``algorithm`` specifies the algorithm to be used: - ``'qfsolve'`` -- Use PARI/GP function ``qfsolve`` - ``'rnfisnorm'`` -- Use PARI's function rnfisnorm (cannot be combined with ``obstruction = True``) - ``'local'`` -- Check if a local solution exists for all primes and infinite places of `\QQ` and apply the Hasse principle (cannot be combined with ``point = True``) - ``'default'`` -- Use ``'qfsolve'`` - ``'magma'`` (requires Magma to be installed) -- delegates the task to the Magma computer algebra system. EXAMPLES:: sage: C = Conic(QQ, [1, 2, -3]) sage: C.has_rational_point(point = True) (True, (1 : 1 : 1)) sage: D = Conic(QQ, [1, 3, -5]) sage: D.has_rational_point(point = True) (False, 3) sage: P.<X,Y,Z> = QQ[] sage: E = Curve(X^2 + Y^2 + Z^2); E Projective Conic Curve over Rational Field defined by X^2 + Y^2 + Z^2 sage: E.has_rational_point(obstruction = True) (False, -1) The following would not terminate quickly with ``algorithm = 'rnfisnorm'`` :: sage: C = Conic(QQ, [1, 113922743, -310146482690273725409]) sage: C.has_rational_point(point = True) (True, (-76842858034579/5424 : -5316144401/5424 : 1)) sage: C.has_rational_point(algorithm = 'local', read_cache = False) True sage: C.has_rational_point(point=True, algorithm='magma', read_cache=False) # optional - magma (True, (30106379962113/7913 : 12747947692/7913 : 1)) TESTS: Create a bunch of conics over `\QQ`, check if ``has_rational_point`` runs without errors and returns consistent answers for all algorithms. Check if all points returned are valid. :: sage: l = Sequence(cartesian_product_iterator([[-1, 0, 1] for i in range(6)])) sage: c = [Conic(QQ, a) for a in l if a != [0,0,0] and a != (0,0,0,0,0,0)] sage: d = [] 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 sage: assert all([e[1][0] == e[2][0] and e[1][0] == e[3][0] for e in d]) 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]]) """ if read_cache: if self._rational_point is not None: if point or obstruction: return True, self._rational_point else: return True if self._local_obstruction is not None: if point or obstruction: return False, self._local_obstruction else: return False if (not point) and self._finite_obstructions == [] and \ self._infinite_obstructions == []: if obstruction: return True, None return True if self.has_singular_point(): if point: return self.has_singular_point(point=True) if obstruction: return True, None return True if algorithm == 'default' or algorithm == 'qfsolve': M = self.symmetric_matrix() M *= lcm([t.denominator() for t in M.list()]) pt = qfsolve(M) if pt in ZZ: if self._local_obstruction is None: self._local_obstruction = pt if point or obstruction: return False, pt return False pt = self.point([pt[0], pt[1], pt[2]]) if point or obstruction: return True, pt return True ret = ProjectiveConic_number_field.has_rational_point( \ self, point = point, \ obstruction = obstruction, \ algorithm = algorithm, \ read_cache = read_cache) if point or obstruction: if is_RingHomomorphism(ret[1]): ret[1] = -1 return ret